diff --git a/nixos/modules/deployment.nix b/nixos/modules/deployment.nix index 773c2fa4287b0afe404a3fba74936680200adeae..db61ba8bdaea0f51ab2d81d11a287658a9a19a2c 100755 --- a/nixos/modules/deployment.nix +++ b/nixos/modules/deployment.nix @@ -102,6 +102,12 @@ in { createHome = true; home = "/home/deployment"; + packages = [ + # update-deployment dependencies + pkgs.morph + pkgs.git + ]; + # Authorize the supplied key to run the deployment update command. openssh.authorizedKeys.keys = [ (restrictedKey { diff --git a/nixos/modules/update-deployment b/nixos/modules/update-deployment index ce71f5f0e66c29270e50ce8db6048fd9ceffe13a..57af331df3bc862770068345dfeca41976ef8455 100755 --- a/nixos/modules/update-deployment +++ b/nixos/modules/update-deployment @@ -1,11 +1,21 @@ -#!/usr/bin/env nix-shell -#!nix-shell -i bash -p morph git +#!/usr/bin/env bash set -euxo pipefail +# XXX I just want to inherit this. Why can't I get it through the environment +# to here? +export NIX_PATH=nixpkgs=https://github.com/PrivateStorageio/nixpkgs/archive/7e71ee63a67bd3e2c190abd982b541603f4f86b0.tar.gz + +# Accept the name of the grid this system is part of as a parameter. This +# lets us pick the correct morph grid source file later on. GRIDNAME=$1 shift +# Determine the right branch name to use for the particular grid we've been +# told we belong to. The grid name is a parameter to this script we can +# re-use it across all of our grids. See deployment.nix for the ssh +# configuration that controls what value is actually passed when an update is +# triggered. case "${GRIDNAME}" in "local") BRANCH="323.continuous-deployment" @@ -24,18 +34,57 @@ case "${GRIDNAME}" in exit 1 esac +# This is where we will maintain a checkout of PrivateStorageio for morph to +# use to compute the desired state. CHECKOUT="${HOME}/PrivateStorageio" + +# This is the address of the git remote where we can get the latest +# PrivateStorageio. REPO="https://whetstone.privatestorage.io/privatestorage/PrivateStorageio.git" if [ -e "${CHECKOUT}" ]; then - git -C "${CHECKOUT}" pull + # It exists already so just make sure it contains the latest changes from + # the canonical repository. + git -C "${CHECKOUT}" fetch else + # It doesn't exist so clone it. git clone "${REPO}" "${CHECKOUT}" - # Check out the right branch ... which also happens to be named after this - # grid (or maybe this grid is named after the branch). - git -C "${CHECKOUT}" checkout "${BRANCH}" fi -echo "$(date --iso-8601=seconds) $(git -C "${CHECKOUT}" rev-parse HEAD)" >> ${HOME}/updates.txt +# Get us to a pristine checkout of the right branch. +git -C "${CHECKOUT}" reset --hard "origin/${BRANCH}" + +# If we happen to be on the local grid then fix the undefined key. +KEY="$(cat /etc/ssh/authorized_keys.d/vagrant)" +sed -i "s_undefined_\"${KEY}\"_" "${CHECKOUT}"/morph/grid/${GRIDNAME}/public-keys/users.nix + +# Compute a log message explaining what we're doing. +LOG_MESSAGE="$(date --iso-8601=seconds) $(git -C "${CHECKOUT}" rev-parse HEAD)" -morph deploy "${CHECKOUT}"/morph/grid/"${GRIDNAME}"/grid.nix switch --on "$(hostname)" +# Make sure we use the right credentials and ask for the right account when +# morph makes the connection. morph's deployment target for each host is the +# full domain name (even though the host is only named with the unqualified +# hostname in the morph grid definition) so compute an ssh config section that +# matches that. Regardless, point this effort at localhost because we *know* +# it's just us we want to update. +cat > ~/.ssh/config <<EOF +Host $(hostname).$(domainname) + HostName 127.0.0.1 + IdentityFile ~/.ssh/morph_key + User root +EOF + +# Make sure known_hosts has the host key in it. +ssh -o StrictHostKeyChecking=no "$(hostname).$(domainname)" ":" + +# Attempt to update just this host. Choose the morph grid definition matching +# the grid we belong to and limit the morph deployment update to the host +# matching our name. morph uses just the bare hostname without the domain +# part. +if morph deploy "${CHECKOUT}"/morph/grid/"${GRIDNAME}"/grid.nix switch --on "$(hostname)"; then + # The deployment succeeded. Record success along with context we pre-computed. + echo "${LOG} OK" >> ${HOME}/updates.txt +else + # Oops. Not so fortunate. Record failure. + echo "${LOG} FAIL" >> ${HOME}/updates.txt +fi