summaryrefslogtreecommitdiff
path: root/index.js
diff options
context:
space:
mode:
Diffstat (limited to 'index.js')
-rw-r--r--index.js140
1 files changed, 140 insertions, 0 deletions
diff --git a/index.js b/index.js
new file mode 100644
index 0000000..5fe88b0
--- /dev/null
+++ b/index.js
@@ -0,0 +1,140 @@
+
+(async () => {
+ const fs = require('fs');
+ const os = require('os');
+ const path = require('path');
+ const pkg = require('./package.json');
+ const chalk = (await import('chalk')).default;
+ const YAML = require('yaml');
+ const uuid = require('uuid');
+ const cp = require('child_process');
+
+ let p;
+
+ function verbose(message) {
+ console.log(chalk.cyan("[snowjail] " + message));
+ }
+
+ function info(message) {
+ console.log(chalk.green("[snowjail] " + message));
+ }
+
+ function warning(message) {
+ console.log(chalk.yellow("[snowjail] " + message));
+ }
+
+ function fatal(message) {
+ console.log(chalk.red("[snowjail] " + message));
+ process.exit(1);
+ }
+
+ verbose("Starting Snowjail v" + pkg.version + "...");
+ warning("Moving to Podman (instead of Docker) is planned before v1.0.0, made sure you have both installed to keep running your applications smoothly");
+
+ if (process.argv[2] !== undefined && fs.existsSync(process.argv[2]) && fs.lstatSync(process.argv[2]).isDirectory()) {
+ global.root = path.resolve(process.argv[2]);
+ verbose("Loading from " + root + "...");
+ } else if (process.argv[2] !== undefined) {
+ if (fs.existsSync(process.argv[2])) {
+ fatal(process.argv[2] + ": not a directory");
+ } else {
+ fatal(process.argv[2] + ": not found");
+ }
+ } else {
+ fatal("missing operand");
+ }
+
+ if (!fs.existsSync(root + "/snowjail.yml") || (fs.existsSync(root + "/snowjail.yml") && !fs.lstatSync(root + "/snowjail.yml").isFile())) {
+ warning("Config not found, creating a default config file");
+ try {
+ fs.writeFileSync(root + "/snowjail.yml", fs.readFileSync(__dirname + "/default.yml").toString().replace("$VERSION$", pkg.version));
+ } catch (e) {
+ fatal("unable to create config: " + e.message);
+ }
+ }
+
+ try {
+ global.config = YAML.parse(fs.readFileSync(root + "/snowjail.yml").toString());
+ } catch (e) {
+ fatal("unable to load config: " + e.message);
+ }
+ verbose("Loaded config")
+
+ verbose("Checking config...")
+ // TODO: Check config for completeness
+
+ verbose("Locking config file...")
+ if (os.platform() === "darwin") {
+ cp.spawnSync("chflags", ["uchg", root]);
+ } else {
+ cp.spawnSync("chattr", ["+i", root]);
+ }
+
+ verbose("Creating jail...")
+ let jid = uuid.v4();
+ let hid = jid.replaceAll("-", "");
+ let args = ["create", "-h", "snowjail-" + hid, "-v", root + ":/snowjail/" + hid, "--name", "sj-" + jid, "-i", "-t"];
+
+ if (config.cpu > 0) {
+ args.push(...["-c", config.cpu]);
+ }
+
+ if (config.ram > 0) {
+ if (config.enforce_ram) {
+ args.push(...["-m", config.ram * 1048576]);
+ } else {
+ args.push(...["--memory-reservation", config.ram * 1048576]);
+ }
+ }
+
+ if (config.hardware) {
+ args.push("--privileged");
+ }
+
+ for (let port of config.ports) {
+ if (port.match(/^[0-9]{1,5}:[0-9]{1,5}$/g) !== null) {
+ args.push(...["-p", port]);
+ }
+ }
+
+ args.push(config.image);
+
+ p = cp.spawnSync("docker", args, { stdio: "inherit" });
+ if (p.exitCode !== 0 && p.exitCode !== undefined) {
+ fatal("unable to create jail: subprocess finished with non-zero exit code: " + p.exitCode);
+ }
+
+ verbose("Starting jail...")
+ p = cp.spawnSync("docker", ["start", "sj-" + jid], { stdio: "inherit" });
+ if (p.exitCode !== 0 && p.exitCode !== undefined) {
+ fatal("unable to start jail: subprocess finished with non-zero exit code: " + p.exitCode);
+ }
+
+ let index = 1;
+ for (let command of config.commands) {
+ info("Running command " + index + "/" + config.commands.length + ": " + command.join(" "));
+ p = cp.spawnSync("docker", ["exec", "-i", "-t", "sj-" + jid, ...command], { stdio: "inherit" });
+ if (p.exitCode !== 0 && p.exitCode !== undefined) {
+ fatal("unable to execute command: subprocess finished with non-zero exit code: " + p.exitCode);
+ }
+
+ index++;
+ }
+
+ verbose("Deleting jail...")
+ p = cp.spawnSync("docker", ["stop", "sj-" + jid], { stdio: "inherit" });
+ if (p.exitCode !== 0 && p.exitCode !== undefined) {
+ fatal("unable to delete jail: subprocess finished with non-zero exit code: " + p.exitCode);
+ }
+ p = cp.spawnSync("docker", ["rm", "sj-" + jid], { stdio: "inherit" });
+ if (p.exitCode !== 0 && p.exitCode !== undefined) {
+ fatal("unable to delete jail: subprocess finished with non-zero exit code: " + p.exitCode);
+ }
+
+ verbose("Unlocking config file...")
+ if (os.platform() === "darwin") {
+ cp.spawnSync("chflags", ["nouchg", root]);
+ } else {
+ cp.spawnSync("chattr", ["-i", root]);
+ }
+})() \ No newline at end of file