ops, cluster: consolidate NixOS provisioning

This moves the diff-and-activate logic from cluster/nix/provision.nix
into ops/{provision,machines}.nix that can be used for both cluster
machines and bgpwtf machines.

The provisioning scripts now live per-NixOS-config, and anything under
ops.machines.$fqdn now has a .passthru.hscloud.provision derivation
which is that script. When ran, it will attempt to deploy onto the
target machine.

There's also a top-level tool at `ops.provision` which builds all
configurations / machines and can be called with the machine name/fqdn
to call the corresponding provisioner script.

clustercfg is changed to use the new provisioning logic.

Change-Id: I258abce9e8e3db42af35af102f32ab7963046353
diff --git a/ops/provision.nix b/ops/provision.nix
new file mode 100644
index 0000000..76054c4
--- /dev/null
+++ b/ops/provision.nix
@@ -0,0 +1,74 @@
+# Top-level wrapper script for calling per-machine provisioners.
+#
+# Given ops.machines."edge01.waw.bgp.wtf".config.passthru.hscloud.provision,
+# this script allows to run it by doing:
+#   $ $(nix-build -A ops.provision) edge01.waw.bgp.wtf
+# Or, to first list all available machines by doing:
+#   $ $(nix-build -A ops.provision)
+#
+# The main logic of the provisioner script is in machines.nix.
+
+{ hscloud, pkgs, lib, ... }:
+
+with lib; with builtins;
+
+let
+
+  # All machines from ops.machines, keyed by FQDN.
+  machines = filterAttrs (n: _: n != "__readTree") hscloud.ops.machines;
+  # Machines' provisioner scripts, keyed by machine FQDN.
+  machineProvisioners = mapAttrs (_: v: v.config.passthru.hscloud.provision) machines;
+  # List of machine FQDNs.
+  machineNames = attrNames machines;
+
+  # User-friendly list of machines by FQDN.
+  machineList = concatStringsSep "\n"
+    (map
+      (name: "  - ${name}")
+      machineNames);
+
+  # Derivation containing bin/provision-FQDN symlinks to machines' provisioners.
+  forest = pkgs.linkFarm "provision-forest"
+    (mapAttrsToList
+      (fqdn: p: { name = "bin/provision-${fqdn}"; path = p; })
+      machineProvisioners);
+in
+
+pkgs.writeScript "provision" ''
+  #!/bin/sh
+  name="$1"
+
+  usage() {
+    echo >&2 "Usage: $0 machine|machine.hswaw.net"
+    echo >&2 "Available machines:"
+    echo >&2 "${machineList}"
+  }
+
+  if [ -z "$name" ]; then
+    usage
+    exit 1
+  fi
+
+  provisioner="${forest}/bin/provision-$name"
+  if [ ! -e "$provisioner" ]; then
+    name="$name.hswaw.net"
+    provisioner="${forest}/bin/provision-$name"
+  fi
+  if [ ! -e "$provisioner" ]; then
+    usage
+    exit 1
+  fi
+  # :^)
+  echo -ne "\e[34mh \e[31ms \e[33mc l \e[34mo \e[32mu \e[31md \e[0m"
+  echo ""
+  echo "Starting provisioner for $name..."
+  echo ""
+  echo "Too slow to evaluate? Equivalent faster command line that rebuilds just one node:"
+  echo "  \$(nix-build -A 'ops.machines.\"$name\".config.passthru.hscloud.provision')"
+  echo ""
+  echo "Or, if you want to deploy the same configuration on different machines, just run"
+  echo "this script again without re-evaluating nix:"
+  echo "  $0 $name"
+  echo ""
+  exec "$provisioner"
+''