summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorralph isenmann2020-09-15 10:18:27 +0200
committerralph isenmann2020-09-15 14:10:57 +0200
commitf5519288f4cd0666d217482c9e19d5485e072d39 (patch)
tree0e716ad729173272846975f65d9eee2bbef1cb26
parent[client] refactoring (diff)
downloadtutor-module-f5519288f4cd0666d217482c9e19d5485e072d39.tar.gz
tutor-module-f5519288f4cd0666d217482c9e19d5485e072d39.tar.xz
tutor-module-f5519288f4cd0666d217482c9e19d5485e072d39.zip
[client] Show and modify Container Details in DetailsWindow
- If the selected image in the ListImageWindow is a container, then open the DetailsWindow with a container-specific panel. - dockerfile and container options are displayed
-rw-r--r--dozentenmodul/src/main/java/org/openslx/dozmod/gui/window/ImageDetailsWindow.java227
-rw-r--r--dozentenmodul/src/main/java/org/openslx/dozmod/gui/window/layout/ImageDetailsWindowLayout.java64
-rw-r--r--dozentenmodul/src/main/java/org/openslx/dozmod/gui/wizard/page/DockerfileUploadPage.java38
3 files changed, 304 insertions, 25 deletions
diff --git a/dozentenmodul/src/main/java/org/openslx/dozmod/gui/window/ImageDetailsWindow.java b/dozentenmodul/src/main/java/org/openslx/dozmod/gui/window/ImageDetailsWindow.java
index 211ff1b7..83578aa3 100644
--- a/dozentenmodul/src/main/java/org/openslx/dozmod/gui/window/ImageDetailsWindow.java
+++ b/dozentenmodul/src/main/java/org/openslx/dozmod/gui/window/ImageDetailsWindow.java
@@ -1,23 +1,18 @@
package org.openslx.dozmod.gui.window;
-import java.awt.Color;
-import java.awt.Frame;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.awt.event.ItemEvent;
-import java.awt.event.ItemListener;
-import java.awt.event.KeyEvent;
-import java.awt.event.MouseAdapter;
-import java.awt.event.MouseEvent;
-import java.awt.event.WindowAdapter;
-import java.awt.event.WindowEvent;
+import java.awt.*;
+import java.awt.event.*;
+import java.io.*;
import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.zip.GZIPInputStream;
+import java.util.zip.GZIPOutputStream;
import javax.swing.AbstractAction;
import javax.swing.JComponent;
@@ -28,8 +23,15 @@ import javax.swing.KeyStroke;
import javax.swing.ListSelectionModel;
import javax.swing.SwingUtilities;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.stream.JsonReader;
import org.apache.log4j.Logger;
import org.apache.thrift.TException;
+import org.kamranzafar.jtar.TarEntry;
+import org.kamranzafar.jtar.TarHeader;
+import org.kamranzafar.jtar.TarInputStream;
+import org.kamranzafar.jtar.TarOutputStream;
import org.openslx.bwlp.thrift.iface.ImageBaseWrite;
import org.openslx.bwlp.thrift.iface.ImageDetailsRead;
import org.openslx.bwlp.thrift.iface.ImagePermissions;
@@ -46,15 +48,13 @@ import org.openslx.dozmod.gui.MainWindow;
import org.openslx.dozmod.gui.changemonitor.AbstractControlWrapper;
import org.openslx.dozmod.gui.changemonitor.DialogChangeMonitor;
import org.openslx.dozmod.gui.changemonitor.DialogChangeMonitor.TextNotEmptyConstraint;
-import org.openslx.dozmod.gui.helper.DateTimeHelper;
-import org.openslx.dozmod.gui.helper.ExpiryDateChooser;
-import org.openslx.dozmod.gui.helper.MessageType;
+import org.openslx.dozmod.gui.helper.*;
import org.openslx.dozmod.gui.helper.PopupMenu;
-import org.openslx.dozmod.gui.helper.UiFeedback;
import org.openslx.dozmod.gui.window.UserListWindow.UserAddedCallback;
import org.openslx.dozmod.gui.window.layout.ImageDetailsWindowLayout;
import org.openslx.dozmod.gui.wizard.ImageUpdateWizard;
import org.openslx.dozmod.gui.wizard.LectureWizard;
+import org.openslx.dozmod.gui.wizard.page.DockerfileUploadPage;
import org.openslx.dozmod.permissions.ImagePerms;
import org.openslx.dozmod.thrift.ImageDetailsActions;
import org.openslx.dozmod.thrift.Session;
@@ -135,6 +135,8 @@ public class ImageDetailsWindow extends ImageDetailsWindowLayout implements UiFe
private AbstractControlWrapper<?> changeListenerPermissions;
+ private ContainerDefinition containerDefinition = new ContainerDefinition();
+
/**
* Constructor
*
@@ -434,6 +436,152 @@ public class ImageDetailsWindow extends ImageDetailsWindowLayout implements UiFe
});
}
+ public static class ContainerDefinition {
+
+ /**
+ * The file to construct a real container, could be an dockerfile or a singularity recipe.
+ */
+ public String containerDescription;
+
+ /**
+ * Further container information.
+ */
+ public DockerfileUploadPage.ContainerMeta containerMeta;
+
+ public String getDescription() {
+ return containerDescription;
+ }
+ public void setDescription(String description) {
+ containerDescription = description;
+ }
+
+
+ public void setContainerDescription(byte[] containerDescription) {
+ this.containerDescription = new String(containerDescription, StandardCharsets.UTF_8);
+ }
+
+ public void setContainerMeta(byte[] containerMeta) {
+ Gson gson = new GsonBuilder().create();
+ this.containerMeta = gson.fromJson(new JsonReader(new InputStreamReader(new ByteArrayInputStream(containerMeta),
+ StandardCharsets.UTF_8)), DockerfileUploadPage.ContainerMeta.class);
+ }
+
+ public DockerfileUploadPage.ContainerMeta getContainerMeta() {
+ return containerMeta;
+ }
+
+
+ public static ContainerDefinition fromByteArray(byte[] rawTarData) {
+
+ ContainerDefinition containerDef = new ContainerDefinition();
+
+ try {
+ TarInputStream tis = new TarInputStream(new GZIPInputStream(new BufferedInputStream(new ByteArrayInputStream(rawTarData))));
+
+ TarEntry entry;
+
+ while((entry = tis.getNextEntry()) != null) {
+ int size = (int)entry.getSize();
+ byte[] rawData = new byte[size];
+ tis.read(rawData,0,size);
+
+ if (entry.getName().equals("dockerfile"))
+ containerDef.setContainerDescription(rawData);
+ if (entry.getName().equals("container_meta.json"))
+ containerDef.setContainerMeta(rawData);
+ }
+
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ return containerDef;
+ }
+
+ /**
+ * Serializes the ContainerMeta and Container Description (e.g. dockerfile) into an tar.gz archive.
+ *
+ * @return A ByteBuffer object of the container definition. Can be uploaded so satellite server.
+ */
+ public ByteBuffer toByteBuffer() {
+
+ ByteBuffer containerDef = null;
+
+ try {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ TarOutputStream output = new TarOutputStream(new GZIPOutputStream(baos));
+
+ Gson gson = new GsonBuilder().setPrettyPrinting().create();
+
+ tarPutFile(output,"container_meta.json", gson.toJson(containerMeta));
+ tarPutFile(output,"dockerfile", containerDescription);
+
+ output.close();
+
+ containerDef = ByteBuffer.wrap(baos.toByteArray());
+
+ } catch (IOException e) {
+ LOGGER.warn("Error writing to tar file", e);
+ }
+
+ return containerDef;
+ }
+ }
+
+ private static void tarPutFile(TarOutputStream output, String fileName, String data) throws IOException
+ {
+ if (data == null)
+ return;
+ tarPutFile(output, fileName, data.getBytes(StandardCharsets.UTF_8));
+ }
+
+ private static void tarPutFile(TarOutputStream output, String fileName, byte[] data) throws IOException
+ {
+ if (data == null)
+ return;
+ output.putNextEntry(new TarEntry(
+ TarHeader.createHeader(fileName, data.length, Util.unixTime(), false, 0644)));
+ output.write(data);
+ }
+
+ /**
+ * Uploads ByteBuffer data to satellite server and stores it in ImageVersion.VirtConfig
+ *
+ * @param imageVersionId Id of the image version, which will be updated.
+ * @param data New virtConfig to store in database.
+ */
+ private void saveContainerDef(final String imageVersionId, ByteBuffer data) {
+
+ try {
+ ThriftManager.getSatClient()
+ .setImageVersionVirtConfig(Session.getSatelliteToken(), imageVersionId, data);
+ } catch (TException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Loads binary file ImageVersion.VirtConfig from the Satellites Database.
+ *
+ * @param selected the selected Image Version. TODO: For now only just the latest Version.
+ */
+ private byte[] loadContainerDef(final ImageVersionDetails selected) {
+
+
+ byte[] rawVirtConfig = null;
+
+ try {
+ ByteBuffer byteBuffer = ThriftManager.getSatClient()
+ .getImageVersionVirtConfig(Session.getSatelliteToken(), selected.versionId);
+ rawVirtConfig = ThriftUtil.unwrapByteBuffer(byteBuffer);
+
+ } catch (TException e) {
+ LOGGER.error("Failed to retrieve virtualizer config for image version " + "'"
+ + image.latestVersionId + ", see trace: ", e);
+ }
+ return rawVirtConfig;
+ }
+
/********************************************************************************
*
* Helper triggering the actual thrift calls
@@ -600,10 +748,28 @@ public class ImageDetailsWindow extends ImageDetailsWindowLayout implements UiFe
return false;
}
}
+
+ // TODO if image is container image upload also ContainerDefinition @link ContainerDefinition
+ if(image.getVirtId().equals(TConst.VIRT_DOCKER))
+ saveContainerDefinition();
+
changeMonitor.reset();
return true;
}
+ private void saveContainerDefinition() {
+ containerDefinition.setDescription(txtContainerDescription.getText());
+
+ containerDefinition.getContainerMeta().setImageName(txtContainerImageName.getText());
+ containerDefinition.getContainerMeta().setRunOptions(txtContainerRun.getText());
+ containerDefinition.getContainerMeta().mountUserDir(chkContainerMountUserDir.isSelected());
+ containerDefinition.getContainerMeta().setUserMountPath(txtContainerMountUserDir.getText());
+
+ // TODO do this only if the containerDefinition has changed.
+ saveContainerDef(image.versions.get(0).versionId,containerDefinition.toByteBuffer());
+ LOGGER.info("Upload new DockerDefinition");
+ }
+
/**
* Helper to save the custom user permissions (those not included in
* ImageBaseWrite).
@@ -762,6 +928,37 @@ public class ImageDetailsWindow extends ImageDetailsWindowLayout implements UiFe
if (virt != null)
lblVirtualizer.setText(virt.getVirtName());
+
+ if(TConst.VIRT_DOCKER.equals(image.getVirtId())){
+ lblVirtualizer.setText(TConst.VIRT_DOCKER);
+ showContainerTab();
+
+ containerDefinition = ContainerDefinition.fromByteArray(loadContainerDef(image.versions.get(0)));
+
+ txtContainerDescription.setText(containerDefinition.getDescription());
+ txtContainerImageName.setText(containerDefinition.getContainerMeta().getImageName());
+ txtContainerRun.setText(containerDefinition.getContainerMeta().getRunOptions());
+ chkContainerMountUserDir.setSelected(containerDefinition.getContainerMeta().mountUserDir());
+ txtContainerMountUserDir.setEnabled(chkContainerMountUserDir.isSelected());
+ txtContainerMountUserDir.setText(containerDefinition.getContainerMeta().getUserMountPath());
+
+ changeMonitor.add(txtContainerDescription).
+ addConstraint(new TextNotEmptyConstraint("Empty Dockerfile not allowed!"));
+ changeMonitor.add(txtContainerImageName)
+ .addConstraint(new TextNotEmptyConstraint("Empty Name not allowed!"));
+ changeMonitor.add(txtContainerRun)
+ .addConstraint(new TextNotEmptyConstraint("No Container Run Options provided!"));
+ // TODO txtContainerMountUserDir txt Field needs a Constraint, only when chkContainerMountUserDir is selected;
+ changeMonitor.add(txtContainerMountUserDir);
+
+ chkContainerMountUserDir.addActionListener(new ActionListener() {
+ @Override public void actionPerformed(ActionEvent e) {
+ containerDefinition.getContainerMeta().mountUserDir(chkContainerMountUserDir.isSelected());
+ txtContainerMountUserDir.setEnabled(chkContainerMountUserDir.isSelected());
+ }
+ });
+ }
+
// fill share mode combo, if not already done
if (cboShareMode.getItemCount() == 0) {
for (ShareMode mode : ShareMode.values()) {
diff --git a/dozentenmodul/src/main/java/org/openslx/dozmod/gui/window/layout/ImageDetailsWindowLayout.java b/dozentenmodul/src/main/java/org/openslx/dozmod/gui/window/layout/ImageDetailsWindowLayout.java
index 2792e9fd..9b86089a 100644
--- a/dozentenmodul/src/main/java/org/openslx/dozmod/gui/window/layout/ImageDetailsWindowLayout.java
+++ b/dozentenmodul/src/main/java/org/openslx/dozmod/gui/window/layout/ImageDetailsWindowLayout.java
@@ -1,11 +1,8 @@
package org.openslx.dozmod.gui.window.layout;
-import java.awt.BorderLayout;
-import java.awt.Color;
-import java.awt.Font;
-import java.awt.Frame;
-import java.awt.GridBagConstraints;
-import java.awt.Insets;
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
import javax.swing.BorderFactory;
import javax.swing.Box;
@@ -20,6 +17,7 @@ import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
+import javax.swing.event.*;
import org.openslx.bwlp.thrift.iface.OperatingSystem;
import org.openslx.bwlp.thrift.iface.ShareMode;
@@ -42,6 +40,14 @@ public abstract class ImageDetailsWindowLayout extends JDialog {
protected final JTextField txtTitle;
protected final JTextArea txtDescription;
+ private final JPanel pnlTabContainer;
+ protected final JTextArea txtContainerDescription;
+ protected final JCheckBox chkContainerMountUserDir;
+ protected final JTextField txtContainerRun;
+ protected final JTextField txtContainerImageName;
+ protected final JTextField txtContainerMountUserDir;
+
+
protected QLabel lblError;
protected final PersonLabel lblOwner;
protected final JButton btnChangeOwner;
@@ -268,6 +274,48 @@ public abstract class ImageDetailsWindowLayout extends JDialog {
grdImagePermissionConfigurator.add(defaultPermissionPane).fill(true, false).expand(false, false);
grdImagePermissionConfigurator.finish(false);
+
+
+
+ /* *******************************************************************************
+ *
+ * Container panel
+ *
+ ********************************************************************************/
+ pnlTabContainer = new JPanel();
+ txtContainerDescription = new JTextArea();
+
+ JPanel pnlContainerMeta = new JPanel();
+ GridManager grdContainerMeta = new GridManager(pnlContainerMeta, 3, false, new Insets(8, 2, 8, 2));
+
+ grdContainerMeta.add(new QLabel("Image Name"));
+ txtContainerImageName = new JTextField();
+ txtContainerImageName.setDocument(txtTitle.getDocument());
+ grdContainerMeta.add(txtContainerImageName,2).fill(true,false);
+ grdContainerMeta.nextRow();
+
+ grdContainerMeta.add(new QLabel("Container Run Options"));
+ txtContainerRun = new JTextField();
+ grdContainerMeta.add(txtContainerRun,2).fill(true,false);
+ grdContainerMeta.nextRow();
+
+ grdContainerMeta.add(new QLabel("Mount User Directory"),1);
+ chkContainerMountUserDir = new JCheckBox();
+ txtContainerMountUserDir = new JTextField();
+ grdContainerMeta.add(chkContainerMountUserDir,1);
+ grdContainerMeta.add(txtContainerMountUserDir,1).fill(true,false);
+ grdContainerMeta.finish(true);
+
+ JScrollPane scrollableTextArea = new JScrollPane(txtContainerDescription);
+ GridManager grdContainer = new GridManager(pnlTabContainer, 1, false, new Insets(8, 2, 8, 2));
+ grdContainer.add(scrollableTextArea,1).fill(true, true).expand(true,true);
+ grdContainer.add(pnlContainerMeta,1).fill(true, false)
+ .anchor(GridBagConstraints.FIRST_LINE_START);
+ grdContainer.add(Box.createVerticalGlue()).fill(true, true);
+ grdContainer.finish(false);
+
+
+
/* *******************************************************************************
*
* Bottom panel for buttons
@@ -299,4 +347,8 @@ public abstract class ImageDetailsWindowLayout extends JDialog {
add(pnlTabs, BorderLayout.CENTER);
add(pnlButtons, BorderLayout.PAGE_END);
}
+
+ protected void showContainerTab() {
+ pnlTabs.addTab("Container", pnlTabContainer);
+ }
}
diff --git a/dozentenmodul/src/main/java/org/openslx/dozmod/gui/wizard/page/DockerfileUploadPage.java b/dozentenmodul/src/main/java/org/openslx/dozmod/gui/wizard/page/DockerfileUploadPage.java
index b4ea3e71..d009f43f 100644
--- a/dozentenmodul/src/main/java/org/openslx/dozmod/gui/wizard/page/DockerfileUploadPage.java
+++ b/dozentenmodul/src/main/java/org/openslx/dozmod/gui/wizard/page/DockerfileUploadPage.java
@@ -169,14 +169,34 @@ public class DockerfileUploadPage extends ContainerUploadPageLayout {
/**
* ContainerMeta is used to store container specific information.
- * An Object of this class will be converted with gson to json file.
+ * An object of this class will be serialized with gson to a json file.
*/
- private class ContainerMeta {
+ public class ContainerMeta {
+
+ private String build_context_url;
private String image_name;
private String run_options;
private Boolean mount_user_dir;
+ private String user_mount_path;
+
+ public ContainerMeta() {
+ build_context_url = "";
+ image_name = "";
+ run_options = "";
+ mount_user_dir = false;
+ user_mount_path = "";
+ }
+
+ public String getBuildContextUrl() {
+ return build_context_url;
+ }
+
+ public void setBuildContextUrl(String buildContextUrl) {
+ this.build_context_url = build_context_url;
+ }
+
public String getRunOptions() {
return run_options;
}
@@ -192,13 +212,23 @@ public class DockerfileUploadPage extends ContainerUploadPageLayout {
public void setImageName(String image_name) {
this.image_name = image_name;
}
- public Boolean getMountUserDir() {
+
+ // TODO (Ralph) i dont like that naming
+ public Boolean mountUserDir() {
return mount_user_dir;
}
- public void setMountUserDir(Boolean mountUserDir) {
+ public void mountUserDir(Boolean mountUserDir) {
this.mount_user_dir = mountUserDir;
}
+
+ public String getUserMountPath() {
+ return user_mount_path;
+ }
+
+ public void setUserMountPath(String userMountPath) {
+ user_mount_path = userMountPath;
+ }
}
private void reactOnUserInput() {