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 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 createContainerImageTypeCBO() { ComboBox cbo = new ComboBox<>( new ComboBox.ComboBoxRenderer() { @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); } }