package org.openslx.dozmod.gui.panel;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.thrift.TException;
import org.openslx.bwlp.thrift.iface.ImageDetailsRead;
import org.openslx.dozmod.gui.Gui;
import org.openslx.dozmod.gui.changemonitor.DialogChangeMonitor;
import org.openslx.dozmod.gui.configurator.ContainerBindMountConfigurator;
import org.openslx.dozmod.gui.control.ComboBox;
import org.openslx.dozmod.gui.control.QLabel;
import org.openslx.dozmod.gui.helper.GridManager;
import org.openslx.dozmod.gui.helper.I18n;
import org.openslx.virtualization.configuration.container.ContainerDefinition;
import org.openslx.virtualization.configuration.container.ContainerMeta;
import org.openslx.virtualization.configuration.container.ContainerMeta.ContainerImageType;
import org.openslx.thrifthelper.ThriftManager;
import org.openslx.util.ThriftUtil;
import javax.swing.*;
import java.awt.*;
import java.nio.ByteBuffer;
public class ContainerPanel extends JPanel {
/**
* Version for serialization.
*/
private static final long serialVersionUID = -3335320345960410582L;
// TODO Set the height of txtContainerRecipe to a proper Value
public static final String IMAGE_CONTEXT = "IMAGE";
public static final String CONTAINER_CONTEXT = "CONTAINER";
private final Logger LOGGER = LogManager.getLogger(ContainerPanel.class);
private final QLabel lblContainerImageType;
private final ComboBox<ContainerMeta.ContainerImageType> cboContainerImageType;
private final JPanel pnlContainerMeta;
private final JTextArea txtContainerRecipe;
private final JTextField txtContainerRun;
private final JTextField txtContainerImageName;
private final JTextField txtContainerRunCommand;
private final ContainerBindMountConfigurator bindMountConfigurator;
private ContainerDefinition containerDefinition = null;
private boolean isFirstTime = true;
public ContainerPanel() {
pnlContainerMeta = new JPanel();
GridManager grdContainerMeta = new GridManager(pnlContainerMeta, 3);
QLabel lblContainerRunOpt = new QLabel(I18n.PANEL.getString("ContainerPanel.ContainerStartOptions.label"));
lblContainerRunOpt.setToolTipText(I18n.PANEL.getString("ContainerPanel.ContainerStartOptions.tooltip"));
txtContainerRun = new JTextField();
grdContainerMeta.add(lblContainerRunOpt);
grdContainerMeta.add(txtContainerRun, 2).fill(true, false).expand(true, false);
grdContainerMeta.nextRow();
QLabel lblContainerRunCommand = new QLabel(I18n.PANEL.getString("ContainerPanel.ContainerRunCommand.label"));
lblContainerRunCommand.setToolTipText(I18n.PANEL.getString("ContainerPanel.ContainerRunCommand.tooltip"));
txtContainerRunCommand = new JTextField();
grdContainerMeta.add(lblContainerRunCommand);
grdContainerMeta.add(txtContainerRunCommand, 2).fill(true, false).expand(true, false);
grdContainerMeta.nextRow();
bindMountConfigurator = new ContainerBindMountConfigurator();
grdContainerMeta.add(bindMountConfigurator, 3).fill(true, true).expand(true, true);
grdContainerMeta.finish(true);
GridManager grdContainer = new GridManager(this, 2, false, new Insets(8, 2, 8, 2));
QLabel lblContainerImageName = new QLabel(I18n.PANEL.getString("ContainerPanel.Label.ImageName.text"));
grdContainer.add(lblContainerImageName);
txtContainerImageName = new JTextField();
grdContainer.add(txtContainerImageName, 1).fill(true, false).expand(true, false);
grdContainer.nextRow();
txtContainerRecipe = new JTextArea();
JScrollPane scrollableTextArea = new JScrollPane(txtContainerRecipe);
scrollableTextArea.setMinimumSize(Gui.getScaledDimension(0, 200));
scrollableTextArea.setPreferredSize(Gui.getScaledDimension(0, 200));
grdContainer.add(scrollableTextArea, 2).fill(true, true).expand(true, true);
lblContainerImageType = new QLabel(I18n.PANEL.getString("ContainerPanel.Label.ContainerImageType.text"));
cboContainerImageType = ContainerPanel.createContainerImageTypeCBO();
grdContainer.add(lblContainerImageType);
grdContainer.add(cboContainerImageType).fill(true, false).expand(true, false);
grdContainer.add(pnlContainerMeta, 2).fill(true, true).expand(true, true);
grdContainer.finish(true);
}
/**
* Retrieves Container specific details for the currently displayed lecture and
* disables gui elements for the specific context.
*
* @param satelliteToken The satelliteToken from which the information are
* retrieved.
* @param image The ImageDetailsRead which has general information
* about Image (name, type, version, etc.)
* @param context In which context this Panel ist used (Image or Lecture)
*/
public void init(String satelliteToken, ImageDetailsRead image, String context) {
try {
byte[] rawVirtConfig;
ByteBuffer byteBuffer = ThriftManager.getSatClient().getImageVersionVirtConfig(satelliteToken,
image.getLatestVersionId());
rawVirtConfig = ThriftUtil.unwrapByteBuffer(byteBuffer);
containerDefinition = ContainerDefinition.fromByteArray(rawVirtConfig);
txtContainerImageName.setText(image.imageName);
txtContainerImageName.setEnabled(false);
// TODO simplify this mess. ContainerBuildContextMethod is to complex or useless
switch (containerDefinition.getContainerImageContext()) {
case DOCKERFILE:
txtContainerRecipe.setText(containerDefinition.getContainerRecipe());
break;
case IMAGE_REPOSITORY:
txtContainerRecipe.setText(containerDefinition.getContainerMeta().getImageRepo());
break;
case GIT_REPOSITORY:
txtContainerRecipe.setText(containerDefinition.getContainerMeta().getBuildContextUrl());
break;
case DOCKER_ARCHIVE:
txtContainerRecipe.setText(containerDefinition.getContainerMeta().getImageName());
break;
default:
LOGGER.error("Unknown Build Context");
break;
}
cboContainerImageType.setSelectedItem(containerDefinition.getContainerMeta().getImageType());
if (context.equals(IMAGE_CONTEXT)) {
initImageDetails();
} else if (context.equals(CONTAINER_CONTEXT)) {
initContainerDetails();
} else {
LOGGER.error("Container Panel init failed: Please use proper context");
}
} catch (TException e) {
LOGGER.error("Failed to retrieve virtualizer config for image version " + "'" + image.getLatestVersionId()
+ ", see trace: ", e);
disableAll();
}
}
private void initImageDetails() {
cboContainerImageType.setSelectedItem(containerDefinition.getContainerMeta().getImageType());
if (containerDefinition.getContainerMeta().getImageType() == ContainerMeta.ContainerImageType.DATA) {
// do not allow changing type if it is data
cboContainerImageType.setEnabled(false);
} else {
// do not allow switching type to data after creation
cboContainerImageType.removeItem(ContainerMeta.ContainerImageType.DATA);
}
// currently, do not allow user to change the Image Repository or Dockerfile in
// the suite.
txtContainerRecipe.setEnabled(false);
// do not show container specific input options
pnlContainerMeta.setVisible(false);
pnlContainerMeta.setEnabled(false);
}
private void initContainerDetails() {
txtContainerRecipe.setEnabled(false);
lblContainerImageType.setVisible(false);
cboContainerImageType.setEditable(false);
cboContainerImageType.setVisible(false);
txtContainerRun.setText(containerDefinition.getContainerMeta().getRunOptions());
txtContainerRunCommand.setText(containerDefinition.getContainerMeta().getRunCommand());
bindMountConfigurator.setData(containerDefinition.getContainerMeta().getBindMountConfig());
}
public void addToChangeMonitor(DialogChangeMonitor changeMonitor) {
if (isFirstTime) {
changeMonitor.add(txtContainerRecipe).addConstraint(new DialogChangeMonitor.TextNotEmptyConstraint(
I18n.PANEL.getString("ContainerPanel.Constraint.NoEmptyDockerfile.text")));
changeMonitor.add(txtContainerRun);
changeMonitor.add(txtContainerRunCommand);
changeMonitor.add(bindMountConfigurator);
changeMonitor.addFixedCombo(cboContainerImageType, null);
isFirstTime = false;
}
}
/**
* Stores changes in ContainerDefinition and Uploads changes to Sat.
*
* @param satelliteToken for current session to communicate with Sat.
* @param image of the image version, which will be updated.
* @return Returns true uf upload successfully finished, false if error
* occurred.
*/
public boolean saveChanges(String satelliteToken, ImageDetailsRead image) {
ContainerDefinition newConDev = new ContainerDefinition(containerDefinition);
newConDev.getContainerMeta()
.setImageType((ContainerMeta.ContainerImageType) cboContainerImageType.getSelectedItem());
newConDev.getContainerMeta().setRunCommand(txtContainerRunCommand.getText());
newConDev.getContainerMeta().setRunOptions(txtContainerRun.getText());
newConDev.getContainerMeta().setBindMountConfig(bindMountConfigurator.getData());
// TODO do I really need this check? Maybe just get every setting and upload it.
if (!newConDev.equals(containerDefinition)) {
LOGGER.info("Update Container Definition");
try {
ThriftManager.getSatClient().setImageVersionVirtConfig(satelliteToken, image.getLatestVersionId(),
newConDev.toByteBuffer());
} catch (TException e) {
LOGGER.error("Upload new ContainerDefinition failed", e);
return false;
}
}
return true;
}
public static ComboBox<ContainerMeta.ContainerImageType> createContainerImageTypeCBO() {
ComboBox<ContainerMeta.ContainerImageType> cbo = new ComboBox<>(
new ComboBox.ComboBoxRenderer<ContainerMeta.ContainerImageType>() {
@Override
public String renderItem(ContainerMeta.ContainerImageType item) {
switch (item) {
case LECTURE:
return "Pool";
case BATCH:
return "Pool/Cluster";
case DATA:
return I18n.PANEL.getString("ContainerPanel.ContainerImageType.Item.label");
default:
return "";
}
}
}, ContainerMeta.ContainerImageType.class);
for (ContainerMeta.ContainerImageType type : ContainerMeta.ContainerImageType.values()) {
// no support for batch container at this time
if (type == ContainerImageType.BATCH)
continue;
cbo.addItem(type);
}
cbo.setSelectedItem(ContainerMeta.ContainerImageType.LECTURE);
return cbo;
}
public void disableAll() {
for (Component component : pnlContainerMeta.getComponents()) {
component.setEnabled(false);
}
txtContainerRecipe.setEnabled(false);
pnlContainerMeta.setEnabled(false);
cboContainerImageType.setEnabled(false);
txtContainerImageName.setEnabled(false);
}
}