Merge remote-tracking branch 'cd/master'
This commit is contained in:
commit
c7a6e74b3d
|
@ -103,103 +103,91 @@ let
|
||||||
plan.method == method &&
|
plan.method == method &&
|
||||||
config.krebs.build.host.name == plan.${side}.host.name;
|
config.krebs.build.host.name == plan.${side}.host.name;
|
||||||
|
|
||||||
start = plan: pkgs.writeDash "backup.${plan.name}" ''
|
start = plan: let
|
||||||
|
login-name = "root";
|
||||||
|
identity = local.host.ssh.privkey.path;
|
||||||
|
ssh = "ssh -i ${shell.escape identity}";
|
||||||
|
local = getAttr plan.method {
|
||||||
|
push = plan.src // { rsync = src-rsync; };
|
||||||
|
pull = plan.dst // { rsync = dst-rsync; };
|
||||||
|
};
|
||||||
|
remote = getAttr plan.method {
|
||||||
|
push = plan.dst // { rsync = dst-rsync; };
|
||||||
|
pull = plan.src // { rsync = src-rsync; };
|
||||||
|
};
|
||||||
|
src-rsync = "rsync";
|
||||||
|
dst-rsync = concatStringsSep " && " [
|
||||||
|
"stat ${shell.escape plan.dst.path} >/dev/null"
|
||||||
|
"mkdir -m 0700 -p ${shell.escape plan.dst.path}/current"
|
||||||
|
"flock -n ${shell.escape plan.dst.path} rsync"
|
||||||
|
];
|
||||||
|
in pkgs.writeScript "backup.${plan.name}" ''
|
||||||
|
#! ${pkgs.bash}/bin/bash
|
||||||
set -efu
|
set -efu
|
||||||
|
start_date=$(date +%s)
|
||||||
|
ssh_target=${shell.escape login-name}@$(${fastest-address remote.host})
|
||||||
${getAttr plan.method {
|
${getAttr plan.method {
|
||||||
push = ''
|
push = ''
|
||||||
identity=${shell.escape plan.src.host.ssh.privkey.path}
|
rsync_src=${shell.escape plan.src.path}
|
||||||
src_path=${shell.escape plan.src.path}
|
rsync_dst=$ssh_target:${shell.escape plan.dst.path}
|
||||||
src=$src_path
|
echo >&2 "update snapshot current; $rsync_src -> $rsync_dst"
|
||||||
dst_user=root
|
|
||||||
dst_host=$(${fastest-address plan.dst.host})
|
|
||||||
dst_port=$(${network-ssh-port plan.dst.host "$dst_host"})
|
|
||||||
dst_path=${shell.escape plan.dst.path}
|
|
||||||
dst=$dst_user@$dst_host:$dst_path
|
|
||||||
echo "update snapshot: current; $src -> $dst" >&2
|
|
||||||
dst_shell() {
|
|
||||||
exec ssh -F /dev/null \
|
|
||||||
-i "$identity" \
|
|
||||||
''${dst_port:+-p $dst_port} \
|
|
||||||
"$dst_user@$dst_host" \
|
|
||||||
-T "$with_dst_path_lock_script"
|
|
||||||
}
|
|
||||||
rsh="ssh -F /dev/null -i $identity ''${dst_port:+-p $dst_port}"
|
|
||||||
local_rsync() {
|
|
||||||
rsync "$@"
|
|
||||||
}
|
|
||||||
remote_rsync=${shell.escape (concatStringsSep " && " [
|
|
||||||
"mkdir -m 0700 -p ${shell.escape plan.dst.path}/current"
|
|
||||||
"exec flock -n ${shell.escape plan.dst.path} rsync"
|
|
||||||
])}
|
|
||||||
'';
|
'';
|
||||||
pull = ''
|
pull = ''
|
||||||
identity=${shell.escape plan.dst.host.ssh.privkey.path}
|
rsync_src=$ssh_target:${shell.escape plan.src.path}
|
||||||
src_user=root
|
rsync_dst=${shell.escape plan.dst.path}
|
||||||
src_host=$(${fastest-address plan.src.host})
|
echo >&2 "update snapshot current; $rsync_dst <- $rsync_src"
|
||||||
src_port=$(${network-ssh-port plan.src.host "$src_host"})
|
|
||||||
src_path=${shell.escape plan.src.path}
|
|
||||||
src=$src_user@$src_host:$src_path
|
|
||||||
dst_path=${shell.escape plan.dst.path}
|
|
||||||
dst=$dst_path
|
|
||||||
echo "update snapshot: current; $dst <- $src" >&2
|
|
||||||
dst_shell() {
|
|
||||||
eval "$with_dst_path_lock_script"
|
|
||||||
}
|
|
||||||
rsh="ssh -F /dev/null -i $identity ''${src_port:+-p $src_port}"
|
|
||||||
local_rsync() {
|
|
||||||
mkdir -m 0700 -p ${shell.escape plan.dst.path}/current
|
|
||||||
flock -n ${shell.escape plan.dst.path} rsync "$@"
|
|
||||||
}
|
|
||||||
remote_rsync=rsync
|
|
||||||
'';
|
'';
|
||||||
}}
|
}}
|
||||||
# Note that this only works because we trust date +%s to produce output
|
${local.rsync} >&2 \
|
||||||
# that doesn't need quoting when used to generate a command string.
|
|
||||||
# TODO relax this requirement by selectively allowing to inject variables
|
|
||||||
# e.g.: ''${shell.quote "exec env NOW=''${shell.unquote "$NOW"} ..."}
|
|
||||||
with_dst_path_lock_script="exec env start_date=$(date +%s) "${shell.escape
|
|
||||||
"flock -n ${shell.escape plan.dst.path} /bin/sh"
|
|
||||||
}
|
|
||||||
local_rsync >&2 \
|
|
||||||
-aAXF --delete \
|
-aAXF --delete \
|
||||||
--rsh="$rsh" \
|
--rsh=${shell.escape ssh} \
|
||||||
--rsync-path="$remote_rsync" \
|
--rsync-path=${shell.escape remote.rsync} \
|
||||||
--link-dest="$dst_path/current" \
|
--link-dest=${shell.escape plan.dst.path}/current \
|
||||||
"$src/" \
|
"$rsync_src/" \
|
||||||
"$dst/.partial"
|
"$rsync_dst/.partial"
|
||||||
dst_shell < ${toFile "backup.${plan.name}.take-snapshots" ''
|
|
||||||
|
dst_exec() {
|
||||||
|
${getAttr plan.method {
|
||||||
|
push = ''exec ${ssh} "$ssh_target" -T "exec$(printf ' %q' "$@")"'';
|
||||||
|
pull = ''exec "$@"'';
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
dst_exec env \
|
||||||
|
start_date="$start_date" \
|
||||||
|
flock -n ${shell.escape plan.dst.path} \
|
||||||
|
/bin/sh < ${toFile "backup.${plan.name}.take-snapshots" ''
|
||||||
set -efu
|
set -efu
|
||||||
: $start_date
|
: $start_date
|
||||||
|
|
||||||
dst=${shell.escape plan.dst.path}
|
dst_path=${shell.escape plan.dst.path}
|
||||||
|
|
||||||
mv "$dst/current" "$dst/.previous"
|
mv "$dst_path/current" "$dst_path/.previous"
|
||||||
mv "$dst/.partial" "$dst/current"
|
mv "$dst_path/.partial" "$dst_path/current"
|
||||||
rm -fR "$dst/.previous"
|
rm -fR "$dst_path/.previous"
|
||||||
echo >&2
|
echo >&2
|
||||||
|
|
||||||
snapshot() {(
|
snapshot() {(
|
||||||
: $ns $format $retain
|
: $ns $format $retain
|
||||||
name=$(date --date="@$start_date" +"$format")
|
name=$(date --date="@$start_date" +"$format")
|
||||||
if ! test -e "$dst/$ns/$name"; then
|
if ! test -e "$dst_path/$ns/$name"; then
|
||||||
echo >&2 "create snapshot: $ns/$name"
|
echo >&2 "create snapshot: $ns/$name"
|
||||||
mkdir -m 0700 -p "$dst/$ns"
|
mkdir -m 0700 -p "$dst_path/$ns"
|
||||||
rsync >&2 \
|
rsync >&2 \
|
||||||
-aAXF --delete \
|
-aAXF --delete \
|
||||||
--link-dest="$dst/current" \
|
--link-dest="$dst_path/current" \
|
||||||
"$dst/current/" \
|
"$dst_path/current/" \
|
||||||
"$dst/$ns/.partial.$name"
|
"$dst_path/$ns/.partial.$name"
|
||||||
mv "$dst/$ns/.partial.$name" "$dst/$ns/$name"
|
mv "$dst_path/$ns/.partial.$name" "$dst_path/$ns/$name"
|
||||||
echo >&2
|
echo >&2
|
||||||
fi
|
fi
|
||||||
case $retain in
|
case $retain in
|
||||||
([0-9]*)
|
([0-9]*)
|
||||||
delete_from=$(($retain + 1))
|
delete_from=$(($retain + 1))
|
||||||
ls -r "$dst/$ns" \
|
ls -r "$dst_path/$ns" \
|
||||||
| sed -n "$delete_from,\$p" \
|
| sed -n "$delete_from,\$p" \
|
||||||
| while read old_name; do
|
| while read old_name; do
|
||||||
echo >&2 "delete snapshot: $ns/$old_name"
|
echo >&2 "delete snapshot: $ns/$old_name"
|
||||||
rm -fR "$dst/$ns/$old_name"
|
rm -fR "$dst_path/$ns/$old_name"
|
||||||
done
|
done
|
||||||
;;
|
;;
|
||||||
(ALL)
|
(ALL)
|
||||||
|
@ -227,24 +215,12 @@ let
|
||||||
| ${pkgs.coreutils}/bin/head -1; }
|
| ${pkgs.coreutils}/bin/head -1; }
|
||||||
'';
|
'';
|
||||||
|
|
||||||
# Note that we don't escape word on purpose, so we can deref shell vars.
|
|
||||||
# TODO type word
|
|
||||||
network-ssh-port = host: word: ''
|
|
||||||
case ${word} in
|
|
||||||
${concatStringsSep ";;\n" (mapAttrsToList
|
|
||||||
(_: net: "(${head net.aliases}) echo ${toString net.ssh.port}")
|
|
||||||
host.nets)};;
|
|
||||||
esac
|
|
||||||
'';
|
|
||||||
|
|
||||||
in out
|
in out
|
||||||
# TODO ionice
|
# TODO ionice
|
||||||
# TODO mail on failed push, pull
|
|
||||||
# TODO mail on missing push
|
# TODO mail on missing push
|
||||||
# TODO don't cancel plans on activation
|
# TODO don't cancel plans on activation
|
||||||
# also, don't hang while deploying at:
|
# also, don't hang while deploying at:
|
||||||
# starting the following units: backup.wu-home-xu.push.service, backup.wu-home-xu.push.timer
|
# starting the following units: backup.wu-home-xu.push.service, backup.wu-home-xu.push.timer
|
||||||
# TODO make sure /bku is properly mounted
|
|
||||||
# TODO make sure that secure hosts cannot backup to insecure ones
|
# TODO make sure that secure hosts cannot backup to insecure ones
|
||||||
# TODO optionally only backup when src and dst are near enough :)
|
# TODO optionally only backup when src and dst are near enough :)
|
||||||
# TODO try using btrfs for snapshots (configurable)
|
# TODO try using btrfs for snapshots (configurable)
|
||||||
|
|
|
@ -218,7 +218,7 @@ let
|
||||||
(filter (hasSuffix ".${cfg.search-domain}")
|
(filter (hasSuffix ".${cfg.search-domain}")
|
||||||
longs);
|
longs);
|
||||||
add-port = a:
|
add-port = a:
|
||||||
if net.ssh.port != null
|
if net.ssh.port != 22
|
||||||
then "[${a}]:${toString net.ssh.port}"
|
then "[${a}]:${toString net.ssh.port}"
|
||||||
else a;
|
else a;
|
||||||
in
|
in
|
||||||
|
@ -228,8 +228,25 @@ let
|
||||||
publicKey = host.ssh.pubkey;
|
publicKey = host.ssh.pubkey;
|
||||||
})
|
})
|
||||||
(filterAttrs (_: host: host.ssh.pubkey != null) cfg.hosts);
|
(filterAttrs (_: host: host.ssh.pubkey != null) cfg.hosts);
|
||||||
|
|
||||||
|
programs.ssh.extraConfig = concatMapStrings
|
||||||
|
(net: ''
|
||||||
|
Host ${toString (net.aliases ++ net.addrs)}
|
||||||
|
Port ${toString net.ssh.port}
|
||||||
|
'')
|
||||||
|
(filter
|
||||||
|
(net: net.ssh.port != 22)
|
||||||
|
(concatMap (host: attrValues host.nets)
|
||||||
|
(mapAttrsToList
|
||||||
|
(_: host: recursiveUpdate host
|
||||||
|
(optionalAttrs (hasAttr config.krebs.search-domain host.nets) {
|
||||||
|
nets."" = host.nets.${config.krebs.search-domain} // {
|
||||||
|
aliases = [host.name];
|
||||||
|
addrs = [];
|
||||||
|
};
|
||||||
|
}))
|
||||||
|
config.krebs.hosts)));
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
in
|
in out
|
||||||
out
|
|
||||||
|
|
|
@ -84,6 +84,14 @@
|
||||||
${pkgs.systemd}/bin/journalctl \
|
${pkgs.systemd}/bin/journalctl \
|
||||||
--lines=${toString plan.journalctl.lines} \
|
--lines=${toString plan.journalctl.lines} \
|
||||||
--output=${plan.journalctl.output} \
|
--output=${plan.journalctl.output} \
|
||||||
|
--since="$(
|
||||||
|
${pkgs.coreutils}/bin/date +'%F %T UTC' -ud "$(
|
||||||
|
${pkgs.systemd}/bin/systemctl show \
|
||||||
|
-p ExecMainStartTimestamp \
|
||||||
|
${shell.escape plan.name} \
|
||||||
|
| ${pkgs.coreutils}/bin/cut -d= -f2-
|
||||||
|
)"
|
||||||
|
)" \
|
||||||
--unit=${shell.escape plan.name}.service
|
--unit=${shell.escape plan.name}.service
|
||||||
} | ${shell.escape cfg.sendmail} -t
|
} | ${shell.escape cfg.sendmail} -t
|
||||||
'';
|
'';
|
||||||
|
|
|
@ -117,8 +117,8 @@ types // rec {
|
||||||
type = submodule {
|
type = submodule {
|
||||||
options = {
|
options = {
|
||||||
port = mkOption {
|
port = mkOption {
|
||||||
type = nullOr int;
|
type = int;
|
||||||
default = null;
|
default = 22;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -14,7 +14,12 @@ with config.krebs.lib;
|
||||||
then trace "Upstream `${upstream.name}' gets overridden by `${override.name}'." override
|
then trace "Upstream `${upstream.name}' gets overridden by `${override.name}'." override
|
||||||
else override;
|
else override;
|
||||||
|
|
||||||
in {
|
in {}
|
||||||
|
// import ./builders.nix args
|
||||||
|
// mapAttrs (_: flip callPackage {})
|
||||||
|
(filterAttrs (_: dir.has-default-nix)
|
||||||
|
(subdirsOf ./.))
|
||||||
|
// {
|
||||||
haskellPackages = pkgs.haskellPackages.override {
|
haskellPackages = pkgs.haskellPackages.override {
|
||||||
overrides = self: super:
|
overrides = self: super:
|
||||||
mapAttrs (name: path: self.callPackage path {})
|
mapAttrs (name: path: self.callPackage path {})
|
||||||
|
@ -29,18 +34,10 @@ with config.krebs.lib;
|
||||||
(builtins.readDir ./haskell-overrides));
|
(builtins.readDir ./haskell-overrides));
|
||||||
};
|
};
|
||||||
|
|
||||||
push = callPackage ./push {
|
|
||||||
inherit (subdirs) get;
|
|
||||||
};
|
|
||||||
|
|
||||||
ReaktorPlugins = callPackage ./Reaktor/plugins.nix {};
|
ReaktorPlugins = callPackage ./Reaktor/plugins.nix {};
|
||||||
|
|
||||||
test = {
|
test = {
|
||||||
infest-cac-centos7 = callPackage ./test/infest-cac-centos7 {};
|
infest-cac-centos7 = callPackage ./test/infest-cac-centos7 {};
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
// import ./builders.nix args
|
|
||||||
// mapAttrs (_: flip callPackage {})
|
|
||||||
(filterAttrs (_: dir.has-default-nix)
|
|
||||||
(subdirsOf ./.));
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,13 +71,13 @@ let
|
||||||
make-public-repo = name: { desc ? null, section ? null, ... }: {
|
make-public-repo = name: { desc ? null, section ? null, ... }: {
|
||||||
inherit name desc section;
|
inherit name desc section;
|
||||||
public = true;
|
public = true;
|
||||||
hooks = {
|
hooks = optionalAttrs (config.krebs.build.host.name == "cd") {
|
||||||
post-receive = pkgs.git-hooks.irc-announce {
|
post-receive = pkgs.git-hooks.irc-announce {
|
||||||
# TODO make nick = config.krebs.build.host.name the default
|
# TODO make nick = config.krebs.build.host.name the default
|
||||||
nick = config.krebs.build.host.name;
|
nick = config.krebs.build.host.name;
|
||||||
channel = "#retiolum";
|
channel = "#retiolum";
|
||||||
server = "cd.retiolum";
|
server = "cd.retiolum";
|
||||||
verbose = config.krebs.build.host.name == "cd";
|
verbose = true;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue