diff options
Diffstat (limited to 'src/main/java')
-rw-r--r-- | src/main/java/io/github/jshipit/Commands.java | 3 | ||||
-rw-r--r-- | src/main/java/io/github/jshipit/ConfigParser.java | 45 | ||||
-rw-r--r-- | src/main/java/io/github/jshipit/ContainerManager.java | 116 | ||||
-rwxr-xr-x | src/main/java/io/github/jshipit/JshipIT.java | 43 | ||||
-rw-r--r-- | src/main/java/io/github/jshipit/Main.java | 2 |
5 files changed, 191 insertions, 18 deletions
diff --git a/src/main/java/io/github/jshipit/Commands.java b/src/main/java/io/github/jshipit/Commands.java index 1b4b913..e4ed5ec 100644 --- a/src/main/java/io/github/jshipit/Commands.java +++ b/src/main/java/io/github/jshipit/Commands.java @@ -41,6 +41,9 @@ class CommandCreate { @Parameter(names = {"--image", "-i"}, description = "Image of the container") public String containerImage; + @Parameter(names = {"--isolated", "-a"}, description = "If the container should be isolated from the host", required = false) + public boolean containerIsolated = true; + @Parameter(names = "--help", help = true) private boolean help; } diff --git a/src/main/java/io/github/jshipit/ConfigParser.java b/src/main/java/io/github/jshipit/ConfigParser.java new file mode 100644 index 0000000..0b19acd --- /dev/null +++ b/src/main/java/io/github/jshipit/ConfigParser.java @@ -0,0 +1,45 @@ +package io.github.jshipit; + +import com.moandjiezana.toml.Toml; + +import java.io.File; +import java.util.List; + +public class ConfigParser { + public String configPath; + + public ConfigParser(String configPath) { + this.configPath = configPath; + } + + public void parseConfig() { + System.out.println("Parsing config"); + Toml toml = new Toml().read(new File(this.configPath)); + } + + public String getString(String key) { + Toml toml = new Toml().read(new File(this.configPath)); + return toml.getString(key); + } + + public boolean getBoolean(String key) { + Toml toml = new Toml().read(new File(this.configPath)); + return toml.getBoolean(key); + } + + public List<String> getList(String key) { + Toml toml = new Toml().read(new File(this.configPath)); + return toml.getList(key); + } + + public long getLong(String key) { + Toml toml = new Toml().read(new File(this.configPath)); + return toml.getLong(key); + } + + public double getDouble(String key) { + Toml toml = new Toml().read(new File(this.configPath)); + return toml.getDouble(key); + } + +} diff --git a/src/main/java/io/github/jshipit/ContainerManager.java b/src/main/java/io/github/jshipit/ContainerManager.java index d276f75..4428465 100644 --- a/src/main/java/io/github/jshipit/ContainerManager.java +++ b/src/main/java/io/github/jshipit/ContainerManager.java @@ -17,18 +17,19 @@ public class ContainerManager { private String containerImage; private String containerTag; private String containerApiRepo; - private String containerCommand; private List<String> containerMounts; + private boolean containerIsolated; private OCIDataStore dataStore; - public ContainerManager(String containerName, String containerImage, String containerTag, String containerApiRepo, String containerRepo, List<String> containerMounts, OCIDataStore dataStore) { + public ContainerManager(String containerName, String containerImage, String containerTag, String containerApiRepo, String containerRepo, boolean containerIsolated, OCIDataStore dataStore) { this.containerName = containerName; this.containerImage = containerImage; this.containerTag = containerTag; this.containerApiRepo = containerApiRepo; this.containerRepo = containerRepo; - this.containerMounts = containerMounts; + this.containerMounts = null; + this.containerIsolated = containerIsolated; this.dataStore = dataStore; } @@ -64,6 +65,36 @@ public class ContainerManager { new File(containerDirectory + "/containerOverlay").mkdirs(); // The upper directory of the overlay mount, user data and any changes to root will be stored here new File(containerDirectory + "/root").mkdirs(); // The root directory of the overlay mount new File(containerDirectory+"/work").mkdirs(); // The work directory of the overlay mount + + // Create the container TOML config file + try { + new File(containerDirectory + "/config.toml").createNewFile(); + FileOutputStream fos = new FileOutputStream(containerDirectory + "/config.toml"); + + String str = "[container]\n"; + str += "command = \"" + this.containerCommand + "\"\n"; + str += "hostname = \"" + this.containerName + "\"\n\n"; + str += "[permissions]\n"; + str += "unshare-all = false\n"; + str += "unshare-net = false\n"; + str += "unshare-user = false\n"; + str += "unshare-ipc = false\n"; + str += "unshare-pid = false\n"; + str += "unshare-uts = true\n"; + str += "unshare-cgroup = false\n"; + str += "mount-dev = true\n"; + str += "mount-proc = true\n"; + str += "mount-bind = []\n"; + + byte[] b = str.getBytes(); + fos.write(b); + fos.close(); + } catch (FileNotFoundException e) { + throw new RuntimeException(e); + } catch (IOException e) { + throw new RuntimeException(e); + } + } /* @@ -104,6 +135,7 @@ public class ContainerManager { public void runCommand() { String containerDirectory = dataStore.getContainerPath(this.containerName); String dataStorePath = dataStore.getPath(); + ConfigParser configParser = new ConfigParser(containerDirectory+"/config.toml"); File configPath = new File(dataStorePath + "/" + this.containerImage + "/" + this.containerTag + "/config"); // Path to the config file of the image String content = null; @@ -122,8 +154,8 @@ public class ContainerManager { config.get("Env").forEach((JsonNode envVar) -> { // Get the environment variables specified in the config file env.add(envVar.asText()); }); - cmd = config.get("Cmd").get(0).asText(); // Get the command specified in the config file - hostname = config.get("Hostname").asText(); // Get the hostname specified in the config file + cmd = configParser.getString("container.command").equals("null") ? config.get("Cmd").get(0).asText() : configParser.getString("container.command"); // Get the command specified in the config file + hostname = configParser.getString("container.hostname").equals("null") ? config.get("Hostname").asText() : configParser.getString("container.hostname"); // Get the hostname specified in the config file } catch (JsonProcessingException e) { throw new RuntimeException(e); } @@ -140,16 +172,12 @@ public class ContainerManager { bwrapCommand.add("--bind "+containerDirectory+"/root / --chdir /"); // Bind the root to / inside the bwrap namespace - if (this.containerMounts != null) { - for (String mount : containerMounts) { - bwrapCommand.add("--bind "+mount.split(":")[0]+" "+mount.split(":")[1]); // Bind the mount to the destination specified in the config file - } + if (!configParser.getBoolean("permissions.unshare-all")) { + processBwrapPermissions(bwrapCommand);// Process the permissions specified in the config file } - bwrapCommand.add("--ro-bind /etc/resolv.conf /etc/resolv.conf"); // Bind the host resolv.conf to the container - bwrapCommand.add("--share-net"); // Share the network namespace - bwrapCommand.add("--unshare-uts --hostname "+ (!hostname.isBlank() ? hostname : this.containerName+"-"+this.containerImage)); // Unshare the UTS namespace and set the hostname bwrapCommand.add("/bin/sh -c '"+(this.containerCommand != null ? this.containerCommand : cmd)+"'"); // Run the command specified in the config file or the command specified in the constructor + SysUtils sysUtils = new SysUtils(); String bwrapCMD = sysUtils.execInBwrap(bwrapCommand.toArray(new String[0]), false); String mountCMD = startContainer(true); @@ -165,6 +193,70 @@ public class ContainerManager { } } + private void processBwrapPermissions(List<String> bwrapCommand) { + ConfigParser configParser = new ConfigParser(dataStore.getContainerPath(this.containerName)+"/config.toml"); + List<String> configMounts = configParser.getList("permissions.mount-bind"); + if (configMounts.size() > 0) { + for (String mount : configMounts) { + bwrapCommand.add("--bind "+mount.split(":")[0]+" "+mount.split(":")[1]); // Bind the mount to the destination specified in the config file + } + } + if (this.containerMounts != null) { + for (String mount : containerMounts) { + bwrapCommand.add("--bind "+mount.split(":")[0]+" "+mount.split(":")[1]); // Bind the mount to the destination specified by the user + } + } + + if (configParser.getBoolean("permissions.mount-dev")) { + bwrapCommand.add("--dev /dev"); // Mount /dev + } + + if (configParser.getBoolean("permissions.mount-proc")) { + bwrapCommand.add("--proc /proc"); // Mount /proc + } + + if (!configParser.getBoolean("permissions.unshare-net")) { + bwrapCommand.add("--ro-bind /etc/resolv.conf /etc/resolv.conf"); // Bind the host resolv.conf to the container + bwrapCommand.add("--share-net"); // Share the network namespace + } else { + bwrapCommand.add("--unshare-net"); // Unshare the network namespace + } + + if (configParser.getBoolean("permissions.unshare-uts")) { + bwrapCommand.add("--unshare-uts"); // Unshare the UTS namespace + + bwrapCommand.add("--hostname "+(configParser.getString("container.hostname").equals("null") ? this.containerName : configParser.getString("container.hostname"))); // Set the hostname + } + + if (configParser.getBoolean("permissions.unshare-user")) { + bwrapCommand.add("--unshare-user"); // Unshare the user namespace + } + + if (configParser.getBoolean("permissions.unshare-ipc")) { + bwrapCommand.add("--unshare-ipc"); // Unshare the IPC namespace + } + + if (configParser.getBoolean("permissions.unshare-pid")) { + bwrapCommand.add("--unshare-pid"); // Unshare the PID namespace + } + + if (configParser.getBoolean("permissions.unshare-uts")) { + bwrapCommand.add("--unshare-uts"); // Unshare the UTS namespace + } + + if (configParser.getBoolean("permissions.unshare-cgroup")) { + bwrapCommand.add("--unshare-cgroup"); // Unshare the cgroup namespace + } + + if (configParser.getBoolean("permissions.mount-dev")) { + bwrapCommand.add("--dev /dev"); // Mount /dev + } + + if (configParser.getBoolean("permissions.mount-proc")) { + bwrapCommand.add("--proc /proc"); // Mount /proc + } + } + /* * Delete a container */ diff --git a/src/main/java/io/github/jshipit/JshipIT.java b/src/main/java/io/github/jshipit/JshipIT.java index 4304051..a48fc8e 100755 --- a/src/main/java/io/github/jshipit/JshipIT.java +++ b/src/main/java/io/github/jshipit/JshipIT.java @@ -49,7 +49,16 @@ public class JshipIT { apiRepo = "registry.docker.io"; } - ContainerManager containerManager = new ContainerManager(commandCreate.containerName, containerImage, commandCreate.containerImage.split(":")[1], apiRepo, containerRepo, null, dataStore); + ContainerManager containerManager = new ContainerManager( + commandCreate.containerName, + containerImage, + commandCreate.containerImage.split(":")[1], + apiRepo, + containerRepo, + commandCreate.containerIsolated, + dataStore + ); + containerManager.createContainer(); } else if (commands.getParsedCommand().equals("pull")) { @@ -67,15 +76,39 @@ public class JshipIT { } System.out.println("Pulling image " + containerImage + " from " + apiRepo + "/" + containerRepo); - dataStore.createImage(apiRepo, containerRepo, containerImage, commandPull.containerImage.split(":")[1]); + dataStore.createImage( + apiRepo, + containerRepo, + containerImage, + commandPull.containerImage.split(":")[1] + ); + } else if (commands.getParsedCommand().equals("start")) { - ContainerManager containerManager = new ContainerManager(commandStart.containerName, commandStart.containerCommand, commandStart.containerMount, dataStore); + ContainerManager containerManager = new ContainerManager( + commandStart.containerName, + commandStart.containerCommand, + commandStart.containerMount, + dataStore + ); + containerManager.runCommand(); } else if (commands.getParsedCommand().equals("shell")) { - ContainerManager containerManager = new ContainerManager(commandShell.containerName, "/bin/sh", commandShell.containerMount, dataStore); // A proper linux system should always have /bin/sh, skill issue if it doesn't + ContainerManager containerManager = new ContainerManager( + commandShell.containerName, + "/bin/sh", // A proper linux system should always have /bin/sh, skill issue if it doesn't + commandShell.containerMount, + dataStore + ); + containerManager.runCommand(); } else if (commands.getParsedCommand().equals("delete")) { - ContainerManager containerManager = new ContainerManager(commandDelete.containerName, null, null, dataStore); + ContainerManager containerManager = new ContainerManager( + commandDelete.containerName, + null, + null, + dataStore + ); + containerManager.deleteContainer(); } } diff --git a/src/main/java/io/github/jshipit/Main.java b/src/main/java/io/github/jshipit/Main.java index 51a88a7..1bac127 100644 --- a/src/main/java/io/github/jshipit/Main.java +++ b/src/main/java/io/github/jshipit/Main.java @@ -3,7 +3,7 @@ package io.github.jshipit; public class Main { public static void main(String[] args) { - new JshipIT(args); // I HATE STATIC FUNCTIONS + new JshipIT(args); } } |