diff options
Diffstat (limited to 'src/main/java/org/openslx/virtualization/configuration/container/ContainerDefinition.java')
-rw-r--r-- | src/main/java/org/openslx/virtualization/configuration/container/ContainerDefinition.java | 225 |
1 files changed, 225 insertions, 0 deletions
diff --git a/src/main/java/org/openslx/virtualization/configuration/container/ContainerDefinition.java b/src/main/java/org/openslx/virtualization/configuration/container/ContainerDefinition.java new file mode 100644 index 0000000..ef493f9 --- /dev/null +++ b/src/main/java/org/openslx/virtualization/configuration/container/ContainerDefinition.java @@ -0,0 +1,225 @@ +package org.openslx.virtualization.configuration.container; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.stream.JsonReader; +import org.apache.log4j.Logger; +import org.kamranzafar.jtar.TarEntry; +import org.kamranzafar.jtar.TarInputStream; +import org.kamranzafar.jtar.TarOutputStream; +import org.openslx.util.TarArchiveUtil; + +import java.io.*; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.util.Objects; +import java.util.zip.GZIPInputStream; +import java.util.zip.GZIPOutputStream; + +public class ContainerDefinition { + + // TODO database needs a refactoring to store container details + // TODO tar.gz of this object is not useful, for smaller dockerfiles it makes the package lager. + + + protected static final Logger LOGGER = Logger.getLogger(ContainerDefinition.class); + + protected static final String CONTAINER_FILE = "dockerfile"; + protected static final String CONTAINER_META_FILE = "container_meta.json"; + + /** + * The file to construct a real container image, could be an dockerfile or a singularity recipe. + */ + public String containerRecipe = ""; + + /** + * Further container information, see {@link ContainerMeta}. + */ + public ContainerMeta containerMeta; + + public ContainerDefinition() { + containerMeta = new ContainerMeta(); + } + + /** + * Copy Constructor + * + * @param containerDef {@link ContainerDefinition} from which to make a deep copy. + */ + public ContainerDefinition(ContainerDefinition containerDef) { + containerRecipe = String.valueOf(containerDef.getContainerRecipe()); + containerMeta = new ContainerMeta(containerDef.getContainerMeta()); + } + + public String getContainerRecipe() { + return containerRecipe; + } + + public void setContainerRecipe(String containerRecipe) { + this.containerRecipe = containerRecipe; + } + + public void setContainerRecipe(File containerRecipeFile) { + this.containerRecipe = readContainerRecipe(containerRecipeFile); + } + + public void setContainerRecipe(byte[] rawContainerRecipe) { + this.containerRecipe = new String(rawContainerRecipe, 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)), + ContainerMeta.class); + } + + public ContainerMeta getContainerMeta() { + return containerMeta; + } + +// public VirtualizationConfigurationDocker createVirtualizationConfig() { +// byte[] rawContainerRecipe = toByteBuffer().array(); +// try { +// return new VirtualizationConfigurationDocker(MetaDataCache.getOperatingSystems(), rawContainerRecipe, +// rawContainerRecipe.length); +// } catch (VirtualizationConfigurationException e) { +// e.printStackTrace(); +// LOGGER.error("Could not create ContainerMetaDataDummy"); +// } +// return null; +// } + + /** + * Utility function to create a {@link ContainerDefinition} object for a byte array downloaded from the server. + * + * @param rawTarData Downloaded tar.gz file from the server as a byte array. + * @return New object of ContainerDefinition. + */ + 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) { + byte[] rawData = new byte[1024]; + ByteArrayOutputStream output = new ByteArrayOutputStream(); + int count; + + // read everything from the TarInputStream for the current Entry + while ((count = tis.read(rawData)) != -1) { + output.write(rawData, 0, count); + } + + if (entry.getName().equals(CONTAINER_FILE)) + containerDef.setContainerRecipe(output.toByteArray()); + if (entry.getName().equals(CONTAINER_META_FILE)) + containerDef.setContainerMeta(output.toByteArray()); + } + + } catch (IOException e) { + LOGGER.error("Could not create a ContainerDefinition Object for rawTarData", e); + } + + 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(); + TarArchiveUtil.tarPutFile(output, CONTAINER_META_FILE, gson.toJson(containerMeta)); + TarArchiveUtil.tarPutFile(output, CONTAINER_FILE, containerRecipe); + output.close(); + + containerDef = ByteBuffer.wrap(baos.toByteArray()); + + } catch (IOException e) { + LOGGER.warn("Could not create a tar file", e); + } + + return containerDef; + } + + private String readContainerRecipe(File file) { + String recipe = null; + try { + + BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file)); + ByteArrayOutputStream rawFile = new ByteArrayOutputStream(); + int count; + byte[] data = new byte[1024]; + while ((count = bis.read(data)) != -1) { + rawFile.write(data, 0, count); + } + + String rawRecipe = new String(rawFile.toByteArray(), StandardCharsets.UTF_8); + + // replace windows by unix EOL + recipe = rawRecipe.replaceAll("\\r\\n", "\n"); + + bis.close(); + + } catch (IOException e) { + LOGGER.error("Could not read Container Recipe", e); + } + return recipe; + } + + /** + * Saves containerRecipe and containerMeta at the provided location. + * + * @param destDir destination directory for containerRecipe and containerMeta. + */ + public void saveLocal(File destDir) { + + writeFile(destDir, containerRecipe, CONTAINER_FILE); + Gson gson = new GsonBuilder().setPrettyPrinting().create(); + writeFile(destDir, gson.toJson(containerMeta), CONTAINER_META_FILE); + } + + private void writeFile(File destDir, String fileContent, String filename) { + File output = new File(destDir, filename); + try { + FileWriter fw = new FileWriter(output); + fw.write(fileContent); + fw.flush(); + fw.close(); + } catch (IOException e) { + e.printStackTrace(); + LOGGER.error("Could not write File", e); + } + } + + public ContainerBuildContextMethod getBuildContextMethod() { + return ContainerBuildContextMethod.fromInt(containerMeta.getBuildContextMethod()); + } + + @Override public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + ContainerDefinition that = (ContainerDefinition) o; + return containerRecipe.equals(that.containerRecipe) && containerMeta.equals(that.containerMeta); + } + + @Override public int hashCode() { + return Objects.hash(containerRecipe, containerMeta); + } +} |