diff options
Diffstat (limited to 'src/main/java/io/github/jshipit')
-rw-r--r-- | src/main/java/io/github/jshipit/BlobDownloader.java | 25 | ||||
-rw-r--r-- | src/main/java/io/github/jshipit/ContainerManager.java | 46 | ||||
-rwxr-xr-x | src/main/java/io/github/jshipit/DockerAPIHelper.java | 4 | ||||
-rwxr-xr-x | src/main/java/io/github/jshipit/JshipIT.java | 5 | ||||
-rw-r--r-- | src/main/java/io/github/jshipit/Mount.java | 48 | ||||
-rwxr-xr-x | src/main/java/io/github/jshipit/OCIDataStore.java | 38 |
6 files changed, 142 insertions, 24 deletions
diff --git a/src/main/java/io/github/jshipit/BlobDownloader.java b/src/main/java/io/github/jshipit/BlobDownloader.java index 91f126e..3aafec4 100644 --- a/src/main/java/io/github/jshipit/BlobDownloader.java +++ b/src/main/java/io/github/jshipit/BlobDownloader.java @@ -6,6 +6,8 @@ import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream; import java.io.*; import java.net.*; +import java.nio.file.Files; +import java.nio.file.Path; public class BlobDownloader extends Thread { @@ -14,13 +16,15 @@ public class BlobDownloader extends Thread { private final String[][] headers; private final String tmpdir; private final boolean extract; + private final String renameTo; - public BlobDownloader(String url, String digest, String[][] headers, String tmpdir, boolean extract) { + public BlobDownloader(String url, String digest, String[][] headers, String tmpdir, boolean extract, String renameTo) { this.url = url; this.digest = digest; this.headers = headers; this.tmpdir = tmpdir; this.extract = extract; + this.renameTo = renameTo; } public void run() { @@ -75,14 +79,27 @@ public class BlobDownloader extends Thread { e.printStackTrace(); } - File extracted = new File(tmpdir + "/" + digest.replace("sha256:", "")); - if (extracted.exists()) { - extracted.delete(); + if (this.renameTo == null) { + return; + } + + Path rename = new File(renameTo).toPath(); + Path current = new File(tmpdir + "/" + digest.replace("sha256:", "")+".tar.gz").toPath(); + try { + Files.move(current, rename); + } catch (IOException e) { + System.out.println("Failed to rename file "+digest); + e.printStackTrace(); } if (!extract) { return; } + + File extracted = new File(tmpdir + "/" + digest.replace("sha256:", "")); + if (extracted.exists()) { + extracted.delete(); + } TarManager tarManager = new TarManager(); try { tarManager.untar(tmpdir + "/" + digest.replace("sha256:", "") + ".tar.gz", extracted); diff --git a/src/main/java/io/github/jshipit/ContainerManager.java b/src/main/java/io/github/jshipit/ContainerManager.java index e8e2dad..3121061 100644 --- a/src/main/java/io/github/jshipit/ContainerManager.java +++ b/src/main/java/io/github/jshipit/ContainerManager.java @@ -1,9 +1,15 @@ package io.github.jshipit; -import java.io.File; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; + +import java.io.*; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; import java.util.UUID; public class ContainerManager { @@ -16,20 +22,22 @@ public class ContainerManager { private String entryCommand; private OCIDataStore dataStore; - public ContainerManager(String containerName, String containerImage, String containerTag, String entryCommand, OCIDataStore dataStore) { + public ContainerManager(String containerName, String containerImage, String containerTag, String entryCommand, String containerApiRepo, String containerRepo, OCIDataStore dataStore) { this.containerName = containerName; this.containerImage = containerImage; this.containerTag = containerTag; this.entryCommand = entryCommand; + this.containerApiRepo = containerApiRepo; + this.containerRepo = containerRepo; this.dataStore = dataStore; } public void createContainer() { System.out.println("Creating container"); - if (!Files.isDirectory(Paths.get(dataStore.getPath() + this.containerImage + "/" + this.containerTag))) { - System.out.println("Image does not exist, pulling now"); - dataStore.createImage(this.containerApiRepo, this.containerRepo, this.containerImage, this.containerTag); + if (!Files.isDirectory(Paths.get(dataStore.getPath() + "/" + this.containerImage + "/" + this.containerTag))) { + System.out.println("Image does not exist"); + return; } if (this.containerID == null) { @@ -43,9 +51,37 @@ public class ContainerManager { new File(containerDirectory + "/containerOverlay").mkdirs(); new File(containerDirectory + "/root").mkdirs(); + } + + public void startContainer() { + System.out.println("Starting container"); + System.out.println("Container ID: " + this.containerID); + System.out.println("Container name: " + this.containerName); + System.out.println("Container image: " + this.containerImage); + System.out.println("Container tag: " + this.containerTag); + System.out.println("Container entry command: " + this.entryCommand); + System.out.println("Container data store: " + this.dataStore.getPath()); + String containerDirectory = dataStore.getContainerPath(this.containerName, this.containerID); + System.out.println("Container directory: " + containerDirectory); + + List<String> content = null; + try { + content = Files.readAllLines(Paths.get(this.dataStore.getPath() + "/" + this.containerImage + "/" + this.containerTag + "/layers")); + } catch (IOException e) { + throw new RuntimeException(e); + } + assert content != null; + List<String> layers = new ArrayList<>(); + for (String line : content) { + layers.add(this.dataStore.getPath() + "/blobs/" + line.replace("sha256:", "")); + } + assert layers.size() > 0; + Mount mount = new Mount(); + String[] diffs = layers.toArray(new String[0]); + mount.overlayMount(diffs, containerDirectory + "/containerOverlay", containerDirectory + "/root"); } diff --git a/src/main/java/io/github/jshipit/DockerAPIHelper.java b/src/main/java/io/github/jshipit/DockerAPIHelper.java index d11f581..21fd9c3 100755 --- a/src/main/java/io/github/jshipit/DockerAPIHelper.java +++ b/src/main/java/io/github/jshipit/DockerAPIHelper.java @@ -138,10 +138,10 @@ public class DockerAPIHelper { } } - public void fetchBlob(String digest, String tmpdir, boolean extract) throws IOException, RuntimeException { + public void fetchBlob(String digest, String tmpdir, boolean extract, String renameTo) throws IOException, RuntimeException { String url = "https://" + this.apiRepo + "/v2/" + this.repository + "/" + this.image + "/blobs/"+digest; String[][] headers = {{"Authorization", "Bearer "+this.apiToken}, {"Accept", "application/vnd/docker.distribution.manifest.v2+json"}}; - BlobDownloader downloader = new BlobDownloader(url, digest, headers, tmpdir, extract); + BlobDownloader downloader = new BlobDownloader(url, digest, headers, tmpdir, extract, renameTo); downloader.start(); } diff --git a/src/main/java/io/github/jshipit/JshipIT.java b/src/main/java/io/github/jshipit/JshipIT.java index 7784128..5ccd96e 100755 --- a/src/main/java/io/github/jshipit/JshipIT.java +++ b/src/main/java/io/github/jshipit/JshipIT.java @@ -43,6 +43,9 @@ public class JshipIT { */ OCIDataStore dataStore = new OCIDataStore("./tmp"); - dataStore.createImage("registry.docker.io","library", "bash", "devel-alpine3.18"); + //dataStore.createImage("registry.docker.io","library", "bash", "devel-alpine3.18"); + ContainerManager containerManager = new ContainerManager("testContainer", "bash", "devel-alpine3.18", "bash", "registry.docker.io", "library", dataStore); + containerManager.createContainer(); + containerManager.startContainer(); } }
\ No newline at end of file diff --git a/src/main/java/io/github/jshipit/Mount.java b/src/main/java/io/github/jshipit/Mount.java new file mode 100644 index 0000000..63b60dd --- /dev/null +++ b/src/main/java/io/github/jshipit/Mount.java @@ -0,0 +1,48 @@ +package io.github.jshipit; + +import com.sun.jna.Library; +import com.sun.jna.Native; +import com.sun.jna.Platform; + +public class Mount { + public interface CLibrary extends Library { + int mount(String source, String target, + String filesystemtype, int mountflags, + String data); + + int umount(String target); + } + + public void mount(String source, String target, + String filesystemtype, int mountflags, + String data) { + CLibrary libc; + + if (Platform.isLinux()) { + libc = Native.load("c", CLibrary.class); + int result = libc.mount(source, target, filesystemtype, mountflags, data); + if (result == 0) { + System.out.println("Device mounted successfully."); + } else { + System.out.println("Device mount failed."); + } + } + } + + public void overlayMount(String[] lower, String upper, String target) { + CLibrary libc; + + if (Platform.isLinux()) { + libc = Native.load("c", CLibrary.class); + int result = libc.mount("overlay", target, "overlay", 0, "lowerdir="+String.join(":", lower)+",upperdir="+upper+",workdir="+target+"/work"); + if (result == 0) { + System.out.println("Device mounted successfully."); + } else { + System.out.println("Device mount failed."); + } + } else { + System.out.println("Platform not supported."); + System.out.println("mount -t overlay overlay -o lowerdir="+String.join(":", lower)+",upperdir="+upper+",workdir="+target+"/work "+target); + } + } +} diff --git a/src/main/java/io/github/jshipit/OCIDataStore.java b/src/main/java/io/github/jshipit/OCIDataStore.java index 3e0b9f3..92db6c2 100755 --- a/src/main/java/io/github/jshipit/OCIDataStore.java +++ b/src/main/java/io/github/jshipit/OCIDataStore.java @@ -52,7 +52,7 @@ public class OCIDataStore { statement.setQueryTimeout(30); // set timeout to 30 sec. statement.executeUpdate("CREATE TABLE IF NOT EXISTS blobs (id INTEGER PRIMARY KEY AUTOINCREMENT, digest TEXT, path TEXT)"); - statement.executeUpdate("CREATE TABLE IF NOT EXISTS containers (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, id TEXT, path TEXT)"); + statement.executeUpdate("CREATE TABLE IF NOT EXISTS containers (containerID INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, id TEXT, path TEXT)"); System.out.println("A new database has been created."); } @@ -111,6 +111,24 @@ public class OCIDataStore { } } + public String getContainerPath(String name, String id) { + String url = "jdbc:sqlite:" + this.databasePath; + + try (Connection conn = DriverManager.getConnection(url)) { + if (conn != null) { + Statement statement = conn.createStatement(); + statement.setQueryTimeout(30); // set timeout to 30 sec. + + ResultSet rs = statement.executeQuery("SELECT * FROM containers WHERE name = '" + name + "' AND id = '" + id + "'"); + return rs.getString("path"); + } + + } catch (SQLException e) { + System.out.println(e.getMessage()); + } + return null; + } + public String createContainerDirectory(String image, String tag, String name, String id) { Path containerPath = Path.of(this.path+"/"+image+"/"+tag+"/"+name+"_"+id); try { @@ -167,7 +185,6 @@ public class OCIDataStore { assert manifest != null; JsonNode layers = manifest.get("layers"); - List<String> digests = new ArrayList<String>(); String layerpath = this.path+"/blobs"; try { Files.createDirectory(Path.of(layerpath)); @@ -178,38 +195,35 @@ public class OCIDataStore { return; } } + List <String> layerDigests = new ArrayList<>(); for (JsonNode layer : layers) { System.out.println("Layer: " + layer); try { if (!isBlobInDatabase(layer.get("digest").asText())) { - api.fetchBlob(layer.get("digest").asText(), layerpath, true); + api.fetchBlob(layer.get("digest").asText(), layerpath, true, null); addBlobToDatabase(layer.get("digest").asText()); + layerDigests.add(layer.get("digest").asText()); } else { System.out.println("Blob already in database: " + layer.get("digest").asText()); } - digests.add(layer.get("digest").asText()); } catch (IOException e) { e.printStackTrace(); } } try { - api.fetchBlob(manifest.get("config").get("digest").asText(), this.path+"/"+image+"/"+tag, false); - File config = new File(this.path+"/"+image+"/"+tag+manifest.get("config").get("digest").asText().replace("sha256:", "")); - config.renameTo(new File(this.path+"/"+image+"/"+tag+"/config")); + Files.write(Path.of(this.path+"/"+image+"/"+tag+"/layers"), layerDigests); } catch (IOException e) { e.printStackTrace(); } - FileWriter writer = null; try { - writer = new FileWriter(this.path+"/"+image+"/"+tag+"/layers"); - writer.write(String.join("\n", digests)); - writer.close(); + api.fetchBlob(manifest.get("config").get("digest").asText(), this.path+"/"+image+"/"+tag, false, this.path+"/"+image+"/"+tag+"/config"); } catch (IOException e) { - throw new RuntimeException(e); + e.printStackTrace(); } + } public String getPath() { |