summaryrefslogtreecommitdiffstats
path: root/krebs/3modules/build
diff options
context:
space:
mode:
authormakefu <github@syntax-fehler.de>2015-09-27 19:41:01 +0200
committermakefu <github@syntax-fehler.de>2015-09-27 19:41:01 +0200
commitbc2bd6e2f6e9295b14e641b82bff62b40641988d (patch)
tree8bc4b655c12b4e0bc33051116a3adb3003463d34 /krebs/3modules/build
parentc65614cdef66c38ff2939928e9072873e19e1c37 (diff)
parent170191034e51fb7e80ff6e6ddcac103ec7527afd (diff)
Merge branch 'before-merge'
Diffstat (limited to 'krebs/3modules/build')
-rw-r--r--krebs/3modules/build/default.nix269
-rw-r--r--krebs/3modules/build/infest/finalize.sh65
-rw-r--r--krebs/3modules/build/infest/install-nix.sh57
-rw-r--r--krebs/3modules/build/infest/prepare.sh74
4 files changed, 465 insertions, 0 deletions
diff --git a/krebs/3modules/build/default.nix b/krebs/3modules/build/default.nix
new file mode 100644
index 000000000..4d2f36a02
--- /dev/null
+++ b/krebs/3modules/build/default.nix
@@ -0,0 +1,269 @@
+{ config, lib, ... }:
+
+with import ../../4lib { inherit lib; };
+
+let
+ target = config.krebs.build // { user.name = "root"; };
+
+ out = {
+ # TODO deprecate krebs.build.host
+ options.krebs.build.host = mkOption {
+ type = types.host;
+ };
+
+ # TODO make krebs.build.profile shell safe
+ options.krebs.build.profile = mkOption {
+ type = types.str;
+ default = "/nix/var/nix/profiles/system";
+ };
+
+ # TODO make krebs.build.target.host :: host
+ options.krebs.build.target = mkOption {
+ type = with types; nullOr str;
+ default = null;
+ };
+
+ # TODO deprecate krebs.build.user
+ options.krebs.build.user = mkOption {
+ type = types.user;
+ };
+
+ options.krebs.build.scripts.deploy = lib.mkOption {
+ type = lib.types.str;
+ default = ''
+ set -efu
+ (${config.krebs.build.scripts._source})
+ ${ssh-target ''
+ ${config.krebs.build.scripts._nix-env}
+ ${config.krebs.build.profile}/bin/switch-to-configuration switch
+ ''}
+ echo OK
+ '';
+ };
+
+ options.krebs.build.scripts.infest = lib.mkOption {
+ type = lib.types.str;
+ default = ''
+ set -efu
+
+ export RSYNC_RSH; RSYNC_RSH="$(type -p ssh) \
+ -o 'HostName ${target.host.infest.addr}' \
+ -o 'Port ${toString target.host.infest.port}' \
+ "
+ ssh() {
+ eval "$RSYNC_RSH \"\$@\""
+ }
+
+ ${ssh-target ''
+ ${readFile ./infest/prepare.sh}
+ ${readFile ./infest/install-nix.sh}
+ ''}
+
+ (${config.krebs.build.scripts._source})
+
+ ${ssh-target ''
+ export PATH; PATH=/root/.nix-profile/bin:$PATH
+
+ src=$(type -p nixos-install)
+ cat_src() {
+ sed < "$src" "$(
+ sed < "$src" -n '
+ /^if ! test -e "\$mountPoint\/\$NIXOS_CONFIG/,/^fi$/=
+ /^nixpkgs=/=
+ /^NIX_PATH=/,/^$/{/./=}
+ ' \
+ | sed 's:$:s/^/#krebs#/:'
+ )"
+ }
+
+ # Location to insert config.krebs.build.scripts._nix-env
+ i=$(sed -n '/^echo "building the system configuration/=' "$src")
+
+ {
+ cat_src | sed -n "1,$i{p}"
+ cat ${doc config.krebs.build.scripts._nix-env}
+ cat_src | sed -n "$i,\''${$i!p}"
+ } > nixos-install
+ chmod +x nixos-install
+
+ # Wrap inserted config.krebs.build.scripts._nix-env into chroot.
+ nix_env=$(cat_src | sed -n '
+ s:.*\(/nix/store/[a-z0-9]*-nix-[0-9.]\+/bin/nix-env\).*:\1:p;T;q
+ ')
+ echo nix-env is $nix_env
+ sed -i '
+ s:^nix-env:chroot $mountPoint '"$nix_env"':
+ ' nixos-install
+
+ ./nixos-install
+
+ ${readFile ./infest/finalize.sh}
+ ''}
+ '';
+ };
+
+ options.krebs.build.scripts._nix-env = lib.mkOption {
+ type = lib.types.str;
+ default = ''
+ set -efu
+ NIX_PATH=${config.krebs.build.source.NIX_PATH} \
+ nix-env \
+ -f '<stockholm>' \
+ -Q \
+ --argstr user-name ${config.krebs.exec.user.name} \
+ --argstr host-name ${target.host.name} \
+ --profile ${config.krebs.build.profile} \
+ --set \
+ -A ${lib.escapeShellArg (lib.concatStringsSep "." [
+ config.krebs.build.user.name
+ config.krebs.build.host.name
+ "system"
+ ])}
+ '';
+ };
+
+ options.krebs.build.scripts._source = lib.mkOption {
+ type = lib.types.str;
+ default = ''
+ set -efu
+ ${
+ lib.concatStringsSep "\n"
+ (lib.mapAttrsToList
+ (name: { scripts, url, ... }: "(${scripts._source})")
+ (config.krebs.build.source.dir //
+ config.krebs.build.source.git))
+ }
+ '';
+ };
+
+ options.krebs.build.source.NIX_PATH = mkOption {
+ type = types.str;
+ default =
+ lib.concatStringsSep ":"
+ (lib.mapAttrsToList (name: _: "${name}=/root/${name}")
+ (config.krebs.build.source.dir //
+ config.krebs.build.source.git));
+ };
+
+ options.krebs.build.source.dir = mkOption {
+ type =
+ let
+ exec = config.krebs.exec;
+ in
+ types.attrsOf (types.submodule ({ config, ... }:
+ let
+ url = "file://${config.host.name}${config.path}";
+
+ can-link = config.host.name == target.host.name;
+ can-push = config.host.name == exec.host.name;
+
+ push-method = ''
+ rsync \
+ --exclude .git \
+ --exclude .graveyard \
+ --exclude old \
+ --exclude tmp \
+ --rsync-path='mkdir -p ${config.target-path} && rsync' \
+ --delete-excluded \
+ -vrLptgoD \
+ ${config.path}/ \
+ ${target.user.name}@${target.host.name}:${config.target-path}
+ '';
+ in
+ {
+ options = {
+ host = mkOption {
+ type = types.host;
+ description = ''
+ define the host where the directory is stored on.
+ XXX: currently it is just used to check if rsync is working,
+ becomes part of url
+ '';
+ };
+ path = mkOption {
+ type = types.str;
+ };
+ scripts._source = mkOption {
+ type = types.str;
+ default =
+ #if can-link then link-method else
+ if can-push then push-method else
+ throw "cannot source ${url}";
+ };
+ target-path = mkOption {
+ type = types.str;
+ default = "/root/${config._module.args.name}";
+ };
+ url = mkOption {
+ type = types.str;
+ default = "file://${config.host.name}${config.path}";
+ };
+ };
+ }
+ ));
+ default = {};
+ };
+
+ options.krebs.build.source.git = mkOption {
+ type =
+ let
+ target = config.krebs.build // { user.name = "root"; };
+ in
+ with types; attrsOf (submodule ({ config, ... }:
+ {
+ options = {
+ url = mkOption {
+ type = types.str; # TODO must be shell safe
+ };
+ rev = mkOption {
+ type = types.str;
+ };
+ scripts._source = mkOption {
+ type = types.str;
+ default = ssh-target ''
+ mkdir -p ${config.target-path}
+ cd ${config.target-path}
+ if ! test -e .git; then
+ git init
+ fi
+ if ! cur_url=$(git config remote.origin.url 2>/dev/null); then
+ git remote add origin ${config.url}
+ elif test "$cur_url" != ${config.url}; then
+ git remote set-url origin ${config.url}
+ fi
+ if test "$(git rev-parse --verify HEAD 2>/dev/null)" != ${config.rev}; then
+ git fetch origin
+ git checkout ${config.rev} -- .
+ git checkout -q ${config.rev}
+ git submodule init
+ git submodule update
+ fi
+ git clean -dxf
+ '';
+ };
+ target-path = mkOption {
+ type = types.str;
+ default = "/root/${config._module.args.name}";
+ };
+ };
+ }
+ ));
+ default = {};
+ };
+ };
+
+ doc = s:
+ let b = "EOF${hashString "sha256" s}"; in
+ ''
+ <<\${b}
+ ${s}
+ ${b}
+ '';
+
+ ssh-target = script:
+ "ssh root@${target.host.name} -T ${doc ''
+ set -efu
+ ${script}
+ ''}";
+
+in out
diff --git a/krebs/3modules/build/infest/finalize.sh b/krebs/3modules/build/infest/finalize.sh
new file mode 100644
index 000000000..ced5a4d4d
--- /dev/null
+++ b/krebs/3modules/build/infest/finalize.sh
@@ -0,0 +1,65 @@
+#! /bin/sh
+set -eux
+{
+ umount /mnt/nix || [ $? -eq 32 ]
+ umount /mnt/boot || [ $? -eq 32 ]
+ umount /mnt/root || [ $? -eq 32 ]
+ umount /mnt || [ $? -eq 32 ]
+ umount /boot || [ $? -eq 32 ]
+
+ PATH=$(set +f; for i in /nix/store/*coreutils*/bin; do :; done; echo $i)
+ export PATH
+
+ mkdir /oldshit
+
+ mv /bin /oldshit/
+ mv /newshit/bin /
+
+ # TODO ensure /boot is empty
+ rmdir /newshit/boot
+
+ # skip /dev
+ rmdir /newshit/dev
+
+ mv /etc /oldshit/
+ mv /newshit/etc /
+
+ # skip /nix (it's already there)
+ rmdir /newshit/nix
+
+ # skip /proc
+ rmdir /newshit/proc
+
+ # skip /run
+ rmdir /newshit/run
+
+ # skip /sys
+ rmdir /newshit/sys
+
+ # skip /root
+ rmdir /newshit/root
+
+ # skip /tmp
+ # TODO rmdir /newshit/tmp
+
+ mv /home /oldshit/
+ mv /newshit/home /
+
+ mv /usr /oldshit/
+ mv /newshit/usr /
+
+ mv /var /oldshit/
+ mv /newshit/var /
+
+ mv /lib /oldshit/
+ mv /lib64 /oldshit/
+ mv /sbin /oldshit/
+ mv /srv /oldshit/
+ mv /opt /oldshit/
+
+
+ mv /newshit /root/ # TODO this one shoult be empty
+ mv /oldshit /root/
+
+ sync
+}
diff --git a/krebs/3modules/build/infest/install-nix.sh b/krebs/3modules/build/infest/install-nix.sh
new file mode 100644
index 000000000..88c8c3e1e
--- /dev/null
+++ b/krebs/3modules/build/infest/install-nix.sh
@@ -0,0 +1,57 @@
+#! /bin/sh
+set -efu
+
+nix_url=https://nixos.org/releases/nix/nix-1.10/nix-1.10-x86_64-linux.tar.bz2
+nix_sha256=504f7a3a85fceffb8766ae5e1005de9e02e489742f5a63cc3e7552120b138bf4
+
+install_nix() {(
+
+ # install nix on host (cf. https://nixos.org/nix/install)
+ if ! test -e /root/.nix-profile/etc/profile.d/nix.sh; then
+ (
+ verify() {
+ printf '%s %s\n' $nix_sha256 $(basename $nix_url) | sha256sum -c
+ }
+ if ! verify; then
+ curl -C - -O "$nix_url"
+ verify
+ fi
+ )
+ nix_src_dir=$(basename $nix_url .tar.bz2)
+ tar jxf $nix_src_dir.tar.bz2
+ mkdir -v -m 0755 -p /nix
+ $nix_src_dir/install
+ fi
+
+ #TODO: make this general or move to prepare
+ if ! mount | grep -Fq '/dev/mapper/centos-root on /mnt/nix type xfs'; then
+ mkdir -p /mnt/nix
+ mount --bind /nix /mnt/nix
+ fi
+
+ . /root/.nix-profile/etc/profile.d/nix.sh
+
+ for i in \
+ bash \
+ coreutils \
+ # This line intentionally left blank.
+ do
+ if ! nix-env -q $i | grep -q .; then
+ nix-env -iA nixpkgs.pkgs.$i
+ fi
+ done
+
+ # install nixos-install
+ if ! type nixos-install 2>/dev/null; then
+ nixpkgs_expr='import <nixpkgs> { system = builtins.currentSystem; }'
+ nixpkgs_path=$(find /nix/store -mindepth 1 -maxdepth 1 -name *-nixpkgs-* -type d)
+ nix-env \
+ --arg config "{ nix.package = ($nixpkgs_expr).nix; }" \
+ --arg pkgs "$nixpkgs_expr" \
+ --arg modulesPath 'throw "no modulesPath"' \
+ -f $nixpkgs_path/nixpkgs/nixos/modules/installer/tools/tools.nix \
+ -iA config.system.build.nixos-install
+ fi
+)}
+
+install_nix "$@"
diff --git a/krebs/3modules/build/infest/prepare.sh b/krebs/3modules/build/infest/prepare.sh
new file mode 100644
index 000000000..07c00c3a5
--- /dev/null
+++ b/krebs/3modules/build/infest/prepare.sh
@@ -0,0 +1,74 @@
+#! /bin/sh
+set -efu
+
+prepare() {(
+ if test -e /etc/os-release; then
+ . /etc/os-release
+ case $ID in
+ centos)
+ case $VERSION_ID in
+ 7)
+ prepare_centos7 "$@"
+ exit
+ ;;
+ esac
+ ;;
+ esac
+ fi
+ echo "$0 prepare: unknown OS" >&2
+ exit -1
+)}
+
+prepare_centos7() {
+ type bzip2 2>/dev/null || yum install -y bzip2
+ type git 2>/dev/null || yum install -y git
+ type rsync 2>/dev/null || yum install -y rsync
+ if ! getent group nixbld >/dev/null; then
+ groupadd -g 30000 -r nixbld
+ fi
+ for i in `seq 1 10`; do
+ if ! getent passwd nixbld$i 2>/dev/null; then
+ useradd \
+ -c "CentOS Nix build user $i" \
+ -d /var/empty \
+ -g 30000 \
+ -G 30000 \
+ -l \
+ -M \
+ -s /sbin/nologin \
+ -u $(expr 30000 + $i) \
+ nixbld$i
+ rm -f /var/spool/mail/nixbld$i
+ fi
+ done
+
+ #
+ # mount install directory
+ #
+
+ if ! mount | grep -Fq '/dev/mapper/centos-root on /mnt type xfs'; then
+ mkdir -p /newshit
+ mount --bind /newshit /mnt
+ fi
+
+ if ! mount | grep -Fq '/dev/sda1 on /mnt/boot type xfs'; then
+ mkdir -p /mnt/boot
+ mount /dev/sda1 /mnt/boot
+ fi
+
+ mount | grep 'on /mnt\>' >&2
+
+ #
+ # prepare install directory
+ #
+
+ mkdir -p /mnt/etc/nixos
+ mkdir -m 0555 -p /mnt/var/empty
+
+ if ! mount | grep -Fq '/dev/mapper/centos-root on /mnt/root type xfs'; then
+ mkdir -p /mnt/root
+ mount --bind /root /mnt/root
+ fi
+}
+
+prepare "$@"