linuxkit-nix/linuxkit-builder/default.nix
2018-09-06 15:06:18 -04:00

258 lines
7.0 KiB
Nix

# Builds a script to start a Linux x86_64 remote builder using LinuxKit. This
# script relies on darwin-x86_64 and linux-x86_64 dependencies so an existing
# remote builder should be used.
# The VM runs SSH with Nix available, so we can use it as a remote builder.
# TODO: Sadly this file has lots of duplication with vmTools.
{ system
, stdenv
, perl
, pixz
, bash
, nix
, pathsFromGraph
, hyperkit
, vpnkit
, linuxkit
, nix-linuxkit-runner
, buildEnv
, writeScript
, writeText
, writeTextFile
, runCommand
, vmTools
, makeInitrd
, shellcheck
, coreutils
, openssh
, gnutar
, gnugrep
, ed
, substituteAll
, pkgsForLinux
, linuxkitKernel ? pkgsForLinux.callPackage ./kernel.nix { }
, storeDir ? builtins.storeDir
, hostPort ? "24083"
}:
let
writeScriptDir = name: text: writeTextFile {inherit name text; executable = true; destination = "/${name}"; };
writeRunitForegroundService = name: run: writeTextFile {inherit name; text = run; executable = true; destination = "/${name}/run"; };
shellcheckedScriptBin = name: src: substitutions: runCommand "shellchecked-${name}" {
sub_src = shellcheckedScript name src substitutions;
} "mkdir -p $out/bin; cp $sub_src $out/bin/${name}";
shellcheckedScript = name: src: substitutions: runCommand "shellchecked-${name}" (substitutions // {
buildInputs = [ shellcheck ];
}) ''
cp ${src} './${name}'
substituteAllInPlace '${name}'
patchShebangs '${name}'
if grep -qE '@[^[:space:]]+@' '${name}'; then
echo "WARNING: Found @alpha@ placeholders!"
grep -E '@[^[:space:]]+@' '${name}'
exit 1
fi
if [ "''${debug:-0}" -eq 1 ]; then
cat '${name}'
fi
shellcheck -x '${name}'
chmod +x '${name}'
mv '${name}' $out
'';
vmToolsLinux = vmTools.override { kernel = linuxkitKernel; pkgs = pkgsForLinux; };
containerIp = "192.168.65.2";
hd = "sda";
systemTarball = import <nixpkgs/nixos/lib/make-system-tarball.nix> {
inherit stdenv perl pixz pathsFromGraph;
contents = [];
storeContents = [
{
object = stage2Init;
symlink = "none";
}
];
};
stage1Init = shellcheckedScript "vm-run-stage1" ./stage-1.sh {
inherit (vmToolsLinux) initrdUtils;
inherit (vmToolsLinux) modulesClosure;
inherit (pkgsForLinux) e2fsprogs;
inherit hd stage2Init;
systemTarballPath = "${systemTarball}/tarball/nixos-system-${system}.tar.xz";
};
sshdConfig = writeText "linuxkit-sshd-config" ''
LogLevel VERBOSE
PermitRootLogin yes
PasswordAuthentication no
ChallengeResponseAuthentication no
'';
stage2Init = shellcheckedScript "vm-run-stage2" ./stage-2.sh rec {
inherit (pkgsForLinux) busybox runit;
inherit storeDir containerIp;
script_modprobe = writeScript "modeprobe" ''
#! /bin/sh
export MODULE_DIR=${linuxkitKernel}/lib/modules/
exec ${pkgsForLinux.kmod}/bin/modprobe "$@"
'';
file_passwd = let
wrapped_shell = writeScript "busybox-sh-wrapper" ''
#!${pkgsForLinux.busybox}/bin/sh
exec ${pkgsForLinux.busybox}/bin/sh -l "$@"
'';
in writeText "passwd" ''
root:x:0:0:System administrator:/root:${wrapped_shell}
sshd:x:1:65534:SSH privilege separation user:/var/empty:${pkgsForLinux.busybox}/bin/false
nixbld1:x:30001:30000:Nix build user 1:/var/empty:${pkgsForLinux.busybox}/bin/false
'';
file_group = writeText "group" ''
nixbld:x:30000:nixbld1
root:x:0:root
'';
file_bashrc = writeScript "bashrc" ''
export PATH="${vmToolsLinux.initrdUtils}/bin:${pkgsForLinux.nix}/bin"
export NIX_SSL_CERT_FILE='${pkgsForLinux.cacert}/etc/ssl/certs/ca-bundle.crt'
'';
script_poweroff = writeScript "poweroff" ''
#!/bin/sh
exec ${pkgsForLinux.busybox}/bin/poweroff -f
'';
file_instructions = writeText "instructions" ''
======================================================================
Remote builder has started.
If this is a fresh VM you need to run the following on the host:
~/.nixpkgs/linuxkit-builder/finish-setup.sh
Exit this VM by running:
kill $(cat ~/.nixpkgs/linuxkit-builder/nix-state/hyperkit.pid)
Or, in this terminal, type 'stop'.
======================================================================
'';
runit_targets = buildEnv {
name = "runit-targets";
paths = [
# Startup
(writeScriptDir "1" ''
#!/bin/sh
echo 'Hello world!'
touch /etc/runit/stopit
chmod 0 /etc/runit/stopit
'')
# Run-time
(writeScriptDir "2" ''
#!/bin/sh
echo "Entering run-time"
cat /proc/uptime
echo "Running services in ${service_targets}..."
exec ${pkgsForLinux.runit}/bin/runsvdir -P ${service_targets}
'')
# Shutdown
(writeScriptDir "3" ''
#!/bin/sh
echo 'Ok, bye...'
'')
];
};
service_targets = buildEnv {
name = "service-targets";
paths = [
(writeRunitForegroundService "acpid" ''
#!/bin/sh
exec ${pkgsForLinux.busybox}/bin/acpid -f
'')
(writeRunitForegroundService "sshd" ''
#!/bin/sh
exec ${pkgsForLinux.openssh}/bin/sshd -D -e -f ${sshdConfig}
'')
(writeRunitForegroundService "vpnkit-expose-port" ''
#!/bin/sh
${pkgsForLinux.go-vpnkit}/bin/vpnkit-expose-port \
-i \
-host-ip 127.0.0.1 -host-port ${hostPort} \
-container-ip 192.168.65.2 -container-port 22 \
-no-local-ip
echo "VPNKit expose port exited $?, which may be fine"
kill -stop $$
'')
(writeRunitForegroundService "vpnkit-forwarder" ''
#!/bin/sh
exec ${pkgsForLinux.go-vpnkit}/bin/vpnkit-forwarder
'')
];
};
};
img = "bzImage";
initrd = makeInitrd {
contents = [
{ object = stage1Init;
symlink = "/init";
}
];
};
builderScript = shellcheckedScript "nix-linuxkit-builder" ./ui.sh {
inherit bash hostPort vpnkit hyperkit linuxkit containerIp coreutils
openssh gnutar;
nix_linuxkit_runner = nix-linuxkit-runner;
boot_files = runCommand "linuxkit-kernel-files" {
kernel_path = "${linuxkitKernel}/${img}";
initrd_path = "${initrd}/initrd";
kernel_cmdline_path = writeText "nix-cmdline"
"console=ttyS0 panic=1 command=${stage2Init} loglevel=7 debug noapic nolapic";
} ''
mkdir $out
cd $out
ln -fs $kernel_path "./nix-kernel"
ln -fs $initrd_path "./nix-initrd.img"
ln -fs $kernel_cmdline_path "./nix-cmdline"
'';
integrated_path = ./integrated.sh;
example_path = ./example.nix;
};
plist = substituteAll {
src = ./daemon.plist;
inherit builderScript;
};
in buildEnv {
name = "linuxkit-builder";
paths = [
(shellcheckedScriptBin "nix-linuxkit-configure" ./configure.sh {
inherit bash hostPort coreutils openssh gnutar gnugrep ed plist nix;
example_path = ./example.nix;
})
];
}