From 509835211f86c8fceefe7cf08cd77ea39dbea5c4 Mon Sep 17 00:00:00 2001 From: Zef Hemel Date: Thu, 31 Oct 2013 10:15:19 -0700 Subject: [PATCH] Work --- configuration.nix | 4 ++ default.nix | 6 +-- src/base.nix | 6 +++ src/bin/nix-docker | 126 +++++++++++++++++++++++++++++++++++++++++++ src/bin/nixdocker.js | 69 ------------------------ src/docker.nix | 20 +------ src/dockerfile.nix | 106 ++++++++++++++++++++++++++++++------ src/package.json | 2 +- zedconfig.json | 12 +++++ 9 files changed, 244 insertions(+), 107 deletions(-) create mode 100644 configuration.nix create mode 100644 src/base.nix create mode 100644 src/bin/nix-docker delete mode 100644 src/bin/nixdocker.js create mode 100644 zedconfig.json diff --git a/configuration.nix b/configuration.nix new file mode 100644 index 0000000..9dbe0aa --- /dev/null +++ b/configuration.nix @@ -0,0 +1,4 @@ +{ config, pkgs, ... }: +{ + services.redis.enable = true; +} \ No newline at end of file diff --git a/default.nix b/default.nix index a81cca3..34c70a5 100644 --- a/default.nix +++ b/default.nix @@ -9,8 +9,8 @@ let }); in nodePackages.buildNodePackage { - name = "nixdocker"; - src = [ { outPath = ./src; name = "nixdocker"; } ]; + name = "nix-docker"; + src = [ { outPath = ./src; name = "nix-docker"; } ]; deps = with nodePackages; [optimist]; - passthru.names = [ "nixdocker" ]; + passthru.names = [ "nix-docker" ]; } \ No newline at end of file diff --git a/src/base.nix b/src/base.nix new file mode 100644 index 0000000..654d72e --- /dev/null +++ b/src/base.nix @@ -0,0 +1,6 @@ +{ config, pkgs, ... }: +{ + config = { + fileSystems."/".device = "/dev/disk/by-label/nixos"; + }; +} \ No newline at end of file diff --git a/src/bin/nix-docker b/src/bin/nix-docker new file mode 100644 index 0000000..0d4aa44 --- /dev/null +++ b/src/bin/nix-docker @@ -0,0 +1,126 @@ +#!/usr/bin/env node + +var argv = require("optimist").argv; +var fs = require("fs"); +var path = require("path"); + +var rootPath = path.resolve(fs.realpathSync(process.argv[1]), "../.."); + +var spawn = require('child_process').spawn; +var execFile = require('child_process').execFile; +var configFile = argv.c || "configuration.nix"; +var imageName = argv.t ? argv.t : "nix-docker-build"; + +var tmpNixStore = "nix_store"; + +if(argv.help) { + console.log("Usage: nix-docker [--dockerfile-only] [--mount-build] [-t imagename] [-c configuration.nix] "); + console.log(" --docker-file-only: generate Docker file, but do not build it."); + console.log(" --mount-build: don't add /nix paths to container, but let them be mounted from host at run-time with -v."); + console.log(" -t: name of the image to build."); + console.log(" -c: path to configuration file to build."); + process.exit(0); +} + +function pipeRun(cmd, args, callback) { + var command = spawn(cmd, args); + command.stdout.pipe(process.stdout); + command.stderr.pipe(process.stderr); + + command.on('close', function(code) { + callback(code); + }); +} + +function build(nix, configPath, callback) { + var nixBuild = spawn('nix-build', [nix, '-I', 'configuration=' + configPath]); + var nixPath; + + nixBuild.stdout.on('data', function(data) { + nixPath = data.toString("ascii"); + }); + nixBuild.stderr.pipe(process.stderr); + + nixBuild.on('close', function(code) { + if (code === 0) { + callback(null, nixPath.trim()); + } else { + callback(code); + } + }); +} + +function cleanup(callback) { + if(!fs.existsSync(tmpNixStore)) { + return callback(); + } + var stats = fs.lstatSync(tmpNixStore); + if(stats.isSymbolicLink()) { + fs.unlinkSync(tmpNixStore); + callback(); + } else { + execFile("chmod", ["-R", "777", tmpNixStore], function() { + execFile("rm", ["-rf", tmpNixStore], callback); + }); + } +} + +function buildImage(dockerFilePath, dockerLines, callback) { + var dockerFile = fs.readFileSync(dockerFilePath + "/Dockerfile").toString("ascii"); + fs.writeFileSync("Dockerfile", dockerFile.replace("<>", dockerLines.join("\n"))); + if(!argv["dockerfile-only"]) { + pipeRun("docker", ["build", "-t", imageName, "."], function(code) { + cleanup(function() { + callback(code); + }); + }); + } +} + +cleanup(function() { + build(rootPath + "/dockerfile.nix", configFile, function(err, dockerFilePath) { + execFile("nix-store", ["-qR", dockerFilePath], {}, function(err, stdout) { + if (err) { + return console.error(err); + } + var paths = stdout.trim().split("\n"); + var dockerLines = []; + + if(argv["big-commit"]) { + fs.mkdirSync(tmpNixStore); + execFile("cp", ["-r", "--no-preserve=ownership"].concat(paths).concat([tmpNixStore]), function(err, stdout, stderr) { + if(err) { + console.log(err); + process.exit(1); + } + console.log(stdout, stderr); + + dockerLines.push("ADD " + tmpNixStore + " /nix/store"); + + console.log("Docker lines", dockerLines); + + buildImage(dockerFilePath, dockerLines, function(code) { + console.log("To run: docker run -t -i " + imageName); + process.exit(code); + }); + }); + } else if(argv["mount-build"]) { + buildImage(dockerFilePath, dockerLines, function(code) { + console.log("To run: docker run -t -i -v /nix/store:/nix/store " + imageName); + process.exit(code); + }); + } else { + fs.symlinkSync("/nix/store", tmpNixStore); + + paths.forEach(function(path) { + dockerLines.push("ADD " + tmpNixStore + path.substring("/nix/store".length) + " " + path); + }); + + buildImage(dockerFilePath, dockerLines, function(code) { + console.log("To run: docker run -t -i " + imageName); + process.exit(code); + }); + } + }); + }); +}); diff --git a/src/bin/nixdocker.js b/src/bin/nixdocker.js deleted file mode 100644 index 14de9c3..0000000 --- a/src/bin/nixdocker.js +++ /dev/null @@ -1,69 +0,0 @@ -#!/usr/bin/env node - -var optimist = require("optimist"); -var fs = require("fs"); -var path = require("path"); - -var rootPath = path.resolve(fs.realpathSync(process.argv[1]), "../.."); - -console.log("Root path", rootPath); - -var spawn = require('child_process').spawn; -var execFile = require('child_process').execFile; - -function pipeRun(cmd, args, callback) { - var command = spawn(cmd, args); - command.stdout.pipe(process.stdout); - command.stderr.pipe(process.stderr); - - command.on('close', function(code) { - callback(code); - }); -} - -function build(nix, configPath, callback) { - var nixBuild = spawn('nix-build', [nix, '-I', 'configuration=' + configPath]); - var nixPath; - - nixBuild.stdout.on('data', function(data) { - nixPath = data.toString("ascii"); - }); - nixBuild.stderr.pipe(process.stderr); - - nixBuild.on('close', function(code) { - if (code === 0) { - callback(null, nixPath.trim()); - } else { - callback(code); - } - }); -} - -build(rootPath + "/docker.nix", "configuration.nix", function(err, startPath) { - build(rootPath + "/dockerfile.nix", "configuration.nix", function(err, dockerFilePath) { - execFile("nix-store", ["-qR", startPath], {}, function(err, stdout) { - if (err) { - return console.error(err); - } - var paths = stdout.split("\n"); - var dockerFile = fs.readFileSync(dockerFilePath + "/Dockerfile").toString("ascii"); - var dockerLines = []; - - if(!fs.existsSync("nix_symlink")) { - fs.symlinkSync("/nix", "nix_symlink"); - } - - paths.forEach(function(path) { - if (path) { - dockerLines.push("ADD " + "nix_symlink" + path.substring("/nix".length) + " " + path); - } - }); - dockerLines.push("CMD " + startPath + "/bin/start"); - fs.writeFileSync("Dockerfile", dockerFile.replace("<>", dockerLines.join("\n"))); - pipeRun("docker", ["build", "-t", "test", "."], function(code) { - fs.unlinkSync("nix_symlink"); - process.exit(code); - }); - }); - }); -}); \ No newline at end of file diff --git a/src/docker.nix b/src/docker.nix index 87bb536..ee65917 100644 --- a/src/docker.nix +++ b/src/docker.nix @@ -3,25 +3,7 @@ }: let inherit (pkgs.lib) concatMapStrings getAttr attrNames hasAttr; - stdenv = pkgs.stdenv; - supervisorConfig = pkgs.writeText "supervisord.conf" '' -[supervisord] -logfile=/tmp/supervisord.log - -${concatMapStrings (name: - let - cfg = getAttr name configuration.services; - in - '' - [program:${name}] - command=${cfg.command} - ${if hasAttr "cwd" cfg then - "directory=${cfg.cwd}" - else ""} - '' - ) (attrNames configuration.services) -} -''; + startScript = pkgs.writeText "start" '' ${pkgs.pythonPackages.supervisor}/bin/supervisord -c ${supervisorConfig} -n ''; diff --git a/src/dockerfile.nix b/src/dockerfile.nix index 583f1f4..3db1f61 100644 --- a/src/dockerfile.nix +++ b/src/dockerfile.nix @@ -1,26 +1,102 @@ { pkgs ? import {} -, configuration ? import { inherit pkgs; } +, configuration ? }: +with pkgs.lib; let - inherit (pkgs.lib) hasAttr concatMapStrings; + config = import { + modules = [ configuration ./base.nix ]; + }; + + services = removeAttrs config.config.systemd.services [ + "acpid" + "network-setup" + "prepare-kexec" + "systemd-sysctl" + "alsa-store" + "nix-daemon" + "rngd" + "systemd-update-utmp" + "cpufreq" + "nix-gc" + "scsi-link-pm" + "systemd-vconsole-setup" + "cron" + "nscd" + "synergy-client" + "update-locatedb" + "dhcpcd" + "ntpd" + "synergy-server" + "post-resume" + "systemd-modules-load" + "klogd" + "pre-sleep" + "systemd-random-seed" + ]; + + isOneShot = cfg: hasAttr "Type" cfg.serviceConfig && cfg.serviceConfig.Type == "oneshot"; + + runServices = filterAttrs (name: cfg: !(isOneShot cfg)) services; + + oneShotServices = filterAttrs (name: cfg: isOneShot cfg) services; + + configToCommand = cfg: if hasAttr "ExecStart" cfg.serviceConfig then + cfg.serviceConfig.ExecStart + else if hasAttr "script" cfg then + pkgs.writeScript "script" '' + #!/bin/sh + ${cfg.script} + '' + else + ""; + + supervisorConfig = pkgs.writeText "supervisord.conf" '' + [supervisord] + logfile=/tmp/supervisord.log + + ${concatMapStrings (name: + let + cfg = getAttr name runServices; + in + '' + [program:${name}] + command=${configToCommand cfg}'' + ) (attrNames runServices) + } + ''; + + extraUsers = config.config.users.extraUsers; + dockerFile = pkgs.writeText "Dockerfile" '' -FROM busybox +FROM ubuntu <> +# Create users ${ - if hasAttr "docker" configuration && hasAttr "ports" configuration.docker then - concatMapStrings (port: "EXPOSE ${toString port}\n") configuration.docker.ports - else + concatMapStrings (name: "RUN /usr/sbin/useradd ${name} || echo\n") (attrNames extraUsers) +} +# Run one shot services +${ + concatMapStrings (name: "RUN ${configToCommand (getAttr name oneShotServices)}\n") (attrNames oneShotServices) +} + + +${ + # if hasAttr "docker" configuration && hasAttr "ports" configuration.docker then + # concatMapStrings (port: "EXPOSE ${toString port}\n") configuration.docker.ports + # else + # "" "" } +CMD ${pkgs.pythonPackages.supervisor}/bin/supervisord -c ${supervisorConfig} -n ''; in pkgs.stdenv.mkDerivation { - name = "dockerfile"; - src = ./.; - - phases = [ "installPhase" ]; - - installPhase = '' - mkdir -p $out - cp ${dockerFile} $out/Dockerfile - ''; + name = "dockerfile"; + src = ./.; + + phases = [ "installPhase" ]; + + installPhase = '' + mkdir -p $out + cp ${dockerFile} $out/Dockerfile + ''; } \ No newline at end of file diff --git a/src/package.json b/src/package.json index d923f55..d349134 100644 --- a/src/package.json +++ b/src/package.json @@ -1,5 +1,5 @@ { - "name" : "nixdocker", + "name" : "nix-docker", "version" : "0.1.0", "dependencies" : { "optimist" : "0.6.0" diff --git a/zedconfig.json b/zedconfig.json new file mode 100644 index 0000000..8f9ab34 --- /dev/null +++ b/zedconfig.json @@ -0,0 +1,12 @@ +{ + "modes": { + "javascript": { + "filenames": ["nix-docker"] + }, + "nix": { + "preferences": { + "tabSize": 2 + } + } + } +} \ No newline at end of file