From d5facc6e64c0617c3dd839a6a831c262694fe365 Mon Sep 17 00:00:00 2001 From: ralph isenmann Date: Tue, 7 Sep 2021 08:50:40 +0200 Subject: [client] allow to select data container images in mount config --- .../gui/control/table/ContainerBindMountTable.java | 11 ++- .../gui/window/ContainerBindMountWindow.java | 19 +++-- .../layout/ContainerBindMountWindowLayout.java | 80 ++++++++++++++++----- .../org/openslx/dozmod/util/ContainerUtils.java | 81 +++++++++++++++------- 4 files changed, 140 insertions(+), 51 deletions(-) diff --git a/dozentenmodul/src/main/java/org/openslx/dozmod/gui/control/table/ContainerBindMountTable.java b/dozentenmodul/src/main/java/org/openslx/dozmod/gui/control/table/ContainerBindMountTable.java index 81c76303..28a5225f 100644 --- a/dozentenmodul/src/main/java/org/openslx/dozmod/gui/control/table/ContainerBindMountTable.java +++ b/dozentenmodul/src/main/java/org/openslx/dozmod/gui/control/table/ContainerBindMountTable.java @@ -1,6 +1,7 @@ package org.openslx.dozmod.gui.control.table; import org.openslx.dozmod.gui.helper.I18n; +import org.openslx.dozmod.util.ContainerUtils; import org.openslx.virtualization.configuration.container.ContainerBindMount; import java.util.ArrayList; @@ -11,7 +12,7 @@ public class ContainerBindMountTable extends ListTable { * Version for serialization. */ private static final long serialVersionUID = -2908607335582645909L; - + public static final ListTableColumn COL_SOURCE = new ListTableColumn( I18n.CONFIGURATOR.getString("ContainerBindMount.BindMountTable.col.src")); public static final ListTableColumn COL_TARGET = new ListTableColumn( @@ -27,7 +28,13 @@ public class ContainerBindMountTable extends ListTable { @Override protected Object getValueAtInternal(ContainerBindMount item, ListTableColumn column) { if (COL_SOURCE == column) - return item.getSource(); + switch (item.getMountType()){ + case DEFAULT: + return item.getSource(); + case CONTAINER_IMAGE: + return ContainerUtils.getImageNameByBaseId(item.getSource()); + } + if (COL_TARGET == column) return item.getTarget(); if (COL_OPTIONS == column) diff --git a/dozentenmodul/src/main/java/org/openslx/dozmod/gui/window/ContainerBindMountWindow.java b/dozentenmodul/src/main/java/org/openslx/dozmod/gui/window/ContainerBindMountWindow.java index fa3cf920..f4f946e6 100644 --- a/dozentenmodul/src/main/java/org/openslx/dozmod/gui/window/ContainerBindMountWindow.java +++ b/dozentenmodul/src/main/java/org/openslx/dozmod/gui/window/ContainerBindMountWindow.java @@ -12,6 +12,7 @@ import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.util.ArrayList; import java.util.List; +import java.util.Objects; public class ContainerBindMountWindow extends ContainerBindMountWindowLayout { @@ -38,7 +39,7 @@ public class ContainerBindMountWindow extends ContainerBindMountWindowLayout { dispose(); } }); - this.cboSourceMountPoint.addItemListener(new ItemListener() { + this.cboSourceMount.addItemListener(new ItemListener() { @Override public void itemStateChanged(ItemEvent e) { isInputComplete(); } @@ -54,7 +55,8 @@ public class ContainerBindMountWindow extends ContainerBindMountWindowLayout { private boolean isInputComplete() { btnSave.setEnabled(false); - if (cboSourceMountPoint == null || cboSourceMountPoint.getSelectedIndex() == 0) { + if (cboSourceMount == null || Objects.equals(cboSourceMount.getSelectedItem(), + ContainerMountChoice.getEmptyChoice())) { header.updateStatus("Source Path is Missing"); return false; } @@ -68,11 +70,14 @@ public class ContainerBindMountWindow extends ContainerBindMountWindowLayout { } private void saveEntry() { - ContainerBindMount bindMount = new ContainerBindMount(); - bindMount.setSource( - ContainerBindMountWindowLayout.SOURCE_MOUNT_POINTS[cboSourceMountPoint.getSelectedIndex()]); - bindMount.setTarget(this.txtBmTarget.getText()); - bindMount.setOptions(this.txtBmOptions.getText()); + + ContainerMountChoice mountChoice = (ContainerMountChoice) this.cboSourceMount.getSelectedItem(); + + ContainerBindMount.ContainerMountType mountType = mountChoice.type; + String source = mountChoice.value; + String target = this.txtBmTarget.getText(); + String option = this.txtBmOptions.getText(); + ContainerBindMount bindMount = new ContainerBindMount(mountType, source, target, option); List oldData = bindMountTable.getData(); List data = new ArrayList<>(oldData); diff --git a/dozentenmodul/src/main/java/org/openslx/dozmod/gui/window/layout/ContainerBindMountWindowLayout.java b/dozentenmodul/src/main/java/org/openslx/dozmod/gui/window/layout/ContainerBindMountWindowLayout.java index 6f6a3cfe..3b542a10 100644 --- a/dozentenmodul/src/main/java/org/openslx/dozmod/gui/window/layout/ContainerBindMountWindowLayout.java +++ b/dozentenmodul/src/main/java/org/openslx/dozmod/gui/window/layout/ContainerBindMountWindowLayout.java @@ -1,13 +1,18 @@ package org.openslx.dozmod.gui.window.layout; +import org.openslx.bwlp.thrift.iface.ImageSummaryRead; import org.openslx.dozmod.gui.Gui; 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.StatusHeader; +import org.openslx.dozmod.util.ContainerUtils; +import org.openslx.virtualization.configuration.container.ContainerBindMount; import javax.swing.*; import java.awt.*; +import java.util.ArrayList; +import java.util.List; public class ContainerBindMountWindowLayout extends JDialog { @@ -19,8 +24,7 @@ public class ContainerBindMountWindowLayout extends JDialog { private static final String title = "Add Bind Mount"; protected final StatusHeader header; - protected final QLabel lblBmSource; - protected final JTextField txtBmSource; + // protected final QLabel lblBmSource; protected final QLabel lblBmTarget; protected final JTextField txtBmTarget; protected final QLabel lblBmOptions; @@ -33,14 +37,14 @@ public class ContainerBindMountWindowLayout extends JDialog { protected static String[] SOURCE_MOUNT_POINTS = { EMPTY_MARKER, TAGS[0], TAGS[1], "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z" }; - protected final ComboBox cboSourceMountPoint = new ComboBox( - new ComboBox.ComboBoxRenderer() { - @Override public String renderItem(String letter) { - if (letter == null) - return null; - return letter; + protected final ComboBox cboSourceMount = new ComboBox<>( + new ComboBox.ComboBoxRenderer() { + @Override public String renderItem(ContainerMountChoice choice) { + if (choice == null) + return ""; + return choice.name; } - }, String.class); + }, ContainerMountChoice.class); public ContainerBindMountWindowLayout(Window modalParent) { super(modalParent, title, ModalityType.APPLICATION_MODAL); @@ -53,16 +57,17 @@ public class ContainerBindMountWindowLayout extends JDialog { add(contentPanel, BorderLayout.CENTER); GridManager grid = new GridManager(contentPanel, 2, true, new Insets(2, 2, 2, 2)); - lblBmSource = new QLabel("Source"); - - txtBmSource = new JTextField(); - cboSourceMountPoint.setModel(new DefaultComboBoxModel<>(SOURCE_MOUNT_POINTS)); - cboSourceMountPoint.setSelectedItem(SOURCE_MOUNT_POINTS[0]); - - grid.add(lblBmSource); - grid.add(cboSourceMountPoint).fill(true, false).expand(true, false); + cboSourceMount.setModel( + new DefaultComboBoxModel<>(generateMountChoices().toArray(new ContainerMountChoice[0]))); + cboSourceMount.setSelectedIndex(0); + grid.add(new QLabel("Source")); + grid.add(cboSourceMount).fill(true, false).expand(true, false); grid.nextRow(); + // grid.add(lblBmSource); + // grid.add(cboSourceMountPoint).fill(true, false).expand(true, false); + // grid.nextRow(); + lblBmTarget = new QLabel("Target"); txtBmTarget = new JTextField(); grid.add(lblBmTarget); @@ -87,10 +92,49 @@ public class ContainerBindMountWindowLayout extends JDialog { grid.add(buttonPane, 2).fill(true, false).expand(true, false); grid.finish(false); - setSize(350, 200); + setSize(350, 300); setResizable(false); if (modalParent != null) { Gui.centerShellOverShell(modalParent, this); } } + + private ArrayList generateMountChoices() { + List dataContainerImages = ContainerUtils.getDataContainerImages(); + ArrayList mountChoices = new ArrayList<>(); + mountChoices.add(ContainerMountChoice.getEmptyChoice()); + + for (int i = 1; i < SOURCE_MOUNT_POINTS.length; i++) { + mountChoices.add(new ContainerMountChoice(ContainerBindMount.ContainerMountType.DEFAULT, + SOURCE_MOUNT_POINTS[i], SOURCE_MOUNT_POINTS[i])); + } + + for (ImageSummaryRead image : dataContainerImages) { + mountChoices.add(new ContainerMountChoice(ContainerBindMount.ContainerMountType.CONTAINER_IMAGE, + image.imageName, image.imageBaseId)); + } + return mountChoices; + } + + protected static class ContainerMountChoice { + + public final ContainerBindMount.ContainerMountType type; + public final String name; + public final String value; + + private static ContainerMountChoice emptyMountChoice = null; + + public ContainerMountChoice(ContainerBindMount.ContainerMountType type, String name, String value) { + this.type = type; + this.name = name; + this.value = value; + } + + public static ContainerMountChoice getEmptyChoice() { + if (emptyMountChoice == null) + emptyMountChoice = new ContainerMountChoice(ContainerBindMount.ContainerMountType.DEFAULT, + "-", "-"); + return emptyMountChoice; + } + } } diff --git a/dozentenmodul/src/main/java/org/openslx/dozmod/util/ContainerUtils.java b/dozentenmodul/src/main/java/org/openslx/dozmod/util/ContainerUtils.java index 3d65ea5d..87f87131 100644 --- a/dozentenmodul/src/main/java/org/openslx/dozmod/util/ContainerUtils.java +++ b/dozentenmodul/src/main/java/org/openslx/dozmod/util/ContainerUtils.java @@ -14,10 +14,13 @@ import org.openslx.dozmod.gui.helper.GridManager; import org.openslx.dozmod.gui.helper.I18n; import org.openslx.dozmod.gui.helper.MessageType; import org.openslx.dozmod.model.ContainerDefinition; +import org.openslx.dozmod.thrift.Session; +import org.openslx.dozmod.thrift.cache.ImageCache; import org.openslx.dozmod.thrift.cache.LectureCache; import org.openslx.thrifthelper.TConst; import org.openslx.thrifthelper.ThriftManager; import org.openslx.util.ThriftUtil; +import org.openslx.virtualization.configuration.container.ContainerMeta; import javax.swing.*; import java.awt.*; @@ -25,6 +28,7 @@ import java.io.*; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; import java.util.Arrays; +import java.util.ArrayList; import java.util.List; /** @@ -33,8 +37,10 @@ import java.util.List; public class ContainerUtils { private static final Logger LOGGER = Logger.getLogger(ContainerUtils.class); + /** - * Checks ImageBaseId of image if already linked with existing Lectures in LectureCache. + * Checks ImageBaseId of image if already linked with existing Lectures in + * LectureCache. * * @param image The image to check. * @return true if the images imageBaseId is already linked with a lecture. @@ -43,7 +49,8 @@ public class ContainerUtils { if (image != null && image.getVirtId().equals(TConst.VIRT_DOCKER)) { List lectureSummaries = LectureCache.get(true); for (LectureSummary lecture : lectureSummaries) { - // lecture.imageBaseId is null when no image linked to it -> NullPointer on equals + // lecture.imageBaseId is null when no image linked to it -> NullPointer on + // equals if (image.imageBaseId.equals(lecture.imageBaseId)) { return true; } @@ -52,6 +59,30 @@ public class ContainerUtils { return false; } + public static List getDataContainerImages() { + String satelliteToken = Session.getSatelliteToken(); + List images = ImageCache.get(true); + List dataContainerImages = new ArrayList<>(); + for (ImageSummaryRead image : images) { + if (image.getVirtId().equals(TConst.VIRT_DOCKER)) { + try { + byte[] rawVirtConfig; + ByteBuffer byteBuffer = ThriftManager.getSatClient().getImageVersionVirtConfig(satelliteToken, + image.getLatestVersionId()); + rawVirtConfig = ThriftUtil.unwrapByteBuffer(byteBuffer); + ContainerDefinition containerDefinition = ContainerDefinition.fromByteArray(rawVirtConfig); + if (containerDefinition.getContainerMeta().getImageType() == ContainerMeta.ContainerImageType.DATA) + dataContainerImages.add(image); + + } catch (TException e) { + // LOGGER.error("Failed to retrieve virtualizer config for image version " + "'" + // + image.getLatestVersionId() + ", see trace: ", e); + } + } + } + return dataContainerImages; + } + public static void showWarning(Component c, Logger logger) { Gui.showMessageBox(c, I18n.WINDOW.getString("LectureDetails.Message.error.containerLinkedWithLecture"), MessageType.WARNING, logger, null); @@ -60,21 +91,21 @@ public class ContainerUtils { public static ContainerDefinition getContainerDefinition(String satelliteToken, String latestVersionId) { byte[] rawVirtConfig = null; try { - ByteBuffer byteBuffer = ThriftManager.getSatClient() - .getImageVersionVirtConfig(satelliteToken, latestVersionId); + ByteBuffer byteBuffer = ThriftManager.getSatClient().getImageVersionVirtConfig(satelliteToken, + latestVersionId); rawVirtConfig = ThriftUtil.unwrapByteBuffer(byteBuffer); } catch (TException e) { - LOGGER.error("Failed to retrieve virtualizer config for image version " + "'" - + latestVersionId + ", see trace: ", e); + LOGGER.error("Failed to retrieve virtualizer config for image version " + "'" + latestVersionId + + ", see trace: ", e); return null; } return ContainerDefinition.fromByteArray(rawVirtConfig); } /** - * Check if a provided tar file contains information about a single docker image. - * To check the validity of the file, the existence of two JSON files is checked - * and one of the files must only contain information for one image. + * Check if a provided tar file contains information about a single docker + * image. To check the validity of the file, the existence of two JSON files is + * checked and one of the files must only contain information for one image. * * The tar file have to be created by the 'docker save ...' command. * @@ -98,7 +129,7 @@ public class ContainerUtils { // because we want only to check manifest.json and repositories file tis.setDefaultSkip(true); while ((entry = tis.getNextEntry()) != null) { - if(!TarHeader.USTAR_MAGIC.equals(entry.getHeader().magic.toString())) + if (!TarHeader.USTAR_MAGIC.equals(entry.getHeader().magic.toString())) break; Arrays.fill(rawData, (byte) 0); output.reset(); @@ -109,8 +140,8 @@ public class ContainerUtils { while ((count = tis.read(rawData)) != -1) { output.write(rawData, 0, count); } - manifestJson = new JsonParser().parse( - new String(output.toByteArray(), StandardCharsets.UTF_8)).getAsJsonArray(); + manifestJson = new JsonParser().parse(new String(output.toByteArray(), StandardCharsets.UTF_8)) + .getAsJsonArray(); } if (entry.getName().equals("repositories")) { @@ -123,20 +154,15 @@ public class ContainerUtils { } tis.close(); // check the json files inside the tar file - if (containsManifest && containsRepositories && manifestJson.isJsonArray() - && manifestJson.size() == 1) { + if (containsManifest && containsRepositories && manifestJson.isJsonArray() && manifestJson.size() == 1) { isValid = true; String repoTag = manifestJson.get(0).getAsJsonObject().get("RepoTags").getAsString(); LOGGER.info(String.format("Tar File contains Docker Image with repoTag=%s", repoTag)); } else if (containsManifest && containsRepositories && manifestJson.isJsonArray() && manifestJson.size() > 1) { - Gui.showMessageBox("Tar File container more then one Images!", MessageType.ERROR, - LOGGER, - null); + Gui.showMessageBox("Tar File container more then one Images!", MessageType.ERROR, LOGGER, null); } else { - Gui.showMessageBox("No valid Tar File with Images provided!", MessageType.ERROR, - LOGGER, - null); + Gui.showMessageBox("No valid Tar File with Images provided!", MessageType.ERROR, LOGGER, null); } } catch (IOException e) { @@ -150,23 +176,30 @@ public class ContainerUtils { GridManager grid = new GridManager(pnlUserInfo, 1, true); JTextArea txtInfoText = new JTextArea(); - txtInfoText.setBorder(BorderFactory.createTitledBorder( - I18n.PAGE_LAYOUT.getString("Info"))); + txtInfoText.setBorder(BorderFactory.createTitledBorder(I18n.PAGE_LAYOUT.getString("Info"))); txtInfoText.setLineWrap(true); txtInfoText.setWrapStyleWord(true); txtInfoText.setEditable(false); txtInfoText.setFocusable(false); txtInfoText.setOpaque(false); txtInfoText.setText(infoText); - grid.add(txtInfoText).fill(true,true); + grid.add(txtInfoText).fill(true, true); grid.nextRow(); JTextField txtUserInfo = new JTextField(); txtUserInfo.setText(imageRepo); - grid.add(txtUserInfo).fill(true,true); + grid.add(txtUserInfo).fill(true, true); grid.finish(true); return pnlUserInfo; } + public static String getImageNameByBaseId(String imageBaseId) { + List images = ImageCache.get(true); + for (ImageSummaryRead image : images) { + if (image.imageBaseId.equals(imageBaseId)) + return image.getImageName(); + } + return imageBaseId; + } } -- cgit v1.2.3-55-g7522