package org.openslx.dozmod.util;
import com.google.gson.JsonArray;
import com.google.gson.JsonParser;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.thrift.TException;
import org.kamranzafar.jtar.TarEntry;
import org.kamranzafar.jtar.TarHeader;
import org.kamranzafar.jtar.TarInputStream;
import org.openslx.bwlp.thrift.iface.ImageSummaryRead;
import org.openslx.bwlp.thrift.iface.LectureSummary;
import org.openslx.dozmod.gui.Gui;
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.*;
import java.io.*;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.List;
/**
* Class with some temporally Helper Functions.
*/
public class ContainerUtils {
private static final Logger LOGGER = LogManager.getLogger(ContainerUtils.class);
/**
* 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.
*/
public static boolean isContainerImageLinked(ImageSummaryRead image) {
if (image != null && image.getVirtId().equals(TConst.VIRT_DOCKER)) {
List<LectureSummary> lectureSummaries = LectureCache.get(true);
for (LectureSummary lecture : lectureSummaries) {
// lecture.imageBaseId is null when no image linked to it -> NullPointer on
// equals
if (image.imageBaseId.equals(lecture.imageBaseId)) {
return true;
}
}
}
return false;
}
public static boolean isDataContainer(ImageSummaryRead image) {
ContainerDefinition containerDefinition = getContainerDefinition(Session.getSatelliteToken(), image.getLatestVersionId());
if (containerDefinition.getContainerMeta().getImageType() == ContainerMeta.ContainerImageType.DATA) {
return true;
}
return false;
}
public static List<ImageSummaryRead> getDataContainerImages() {
String satelliteToken = Session.getSatelliteToken();
List<ImageSummaryRead> images = ImageCache.get(true);
List<ImageSummaryRead> dataContainerImages = new ArrayList<>();
for (ImageSummaryRead image : images) {
if (image.getVirtId().equals(TConst.VIRT_DOCKER)) {
ContainerDefinition containerDefinition = getContainerDefinition(satelliteToken, image.getLatestVersionId());
if (containerDefinition.getContainerMeta().getImageType() == ContainerMeta.ContainerImageType.DATA)
dataContainerImages.add(image);
}
}
return dataContainerImages;
}
public static void showWarning(Component c, String message, Logger logger) {
Gui.showMessageBox(c, message,
MessageType.WARNING, logger, null);
}
public static ContainerDefinition getContainerDefinition(String satelliteToken, String latestVersionId) {
byte[] rawVirtConfig = null;
try {
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);
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.
*
* The tar file have to be created by the 'docker save ...' command.
*
* @param tarFile the user selected tar file.
* @return true if the images imageBaseId is already linked with a lecture.
*/
public static boolean isValidTar(File tarFile) {
boolean isValid = false;
boolean containsManifest = false;
boolean containsRepositories = false;
JsonArray manifestJson = null;
try {
TarInputStream tis = new TarInputStream(new FileInputStream(tarFile));
ByteArrayOutputStream output = new ByteArrayOutputStream();
byte[] rawData = new byte[1024];
TarEntry entry;
// setDefaultSkip seems to fasten things up while processing the file,
// 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()))
break;
Arrays.fill(rawData, (byte) 0);
output.reset();
int count = 0;
if (entry.getName().equals("manifest.json")) {
containsManifest = true;
while ((count = tis.read(rawData)) != -1) {
output.write(rawData, 0, count);
}
manifestJson = JsonParser.parseString(new String(output.toByteArray(), StandardCharsets.UTF_8))
.getAsJsonArray();
}
if (entry.getName().equals("repositories")) {
containsRepositories = true;
// dont read the file, no checks for the Content
}
if (containsManifest && containsRepositories)
break;
}
tis.close();
// check the json files inside the tar file
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);
} else {
Gui.showMessageBox("No valid Tar File with Images provided!", MessageType.ERROR, LOGGER, null);
}
} catch (IOException e) {
LOGGER.error("IOError while processing tar file", e);
}
return isValid;
}
public static JPanel createDownloadContainerInfo(String imageRepo, String infoText) {
JPanel pnlUserInfo = new JPanel();
GridManager grid = new GridManager(pnlUserInfo, 1, true);
JTextArea txtInfoText = new JTextArea();
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.nextRow();
JTextField txtUserInfo = new JTextField();
txtUserInfo.setText(imageRepo);
grid.add(txtUserInfo).fill(true, true);
grid.finish(true);
return pnlUserInfo;
}
public static String getImageNameByBaseId(String imageBaseId) {
List<ImageSummaryRead> images = ImageCache.get(true);
for (ImageSummaryRead image : images) {
if (image.imageBaseId.equals(imageBaseId))
return image.getImageName();
}
return imageBaseId;
}
}