packages feed

hail-0.1.0.3: hail-systemd-bootstrap.nix

# | Build a profile usable by 'hail' to spin up 'hail' instances for
# a set of services on systemd-based systems.
#
# The profiles generated live in the 'hail-profiles' nix profile
# subdirectory
#
# Example: Create a hydra jobset 'infra.staging' with job 'foo-bar-box'
# defined by:
#   let hail-systemd-bootstrap = pkgs.callPackage ./hail-systemd-bootstrap.nix {};
#   in
#     hail-systemd-bootstrap
#       { services =
#           { foo = "https://hydra.example.com/job/foo/staging/foo";
#             bar = "https://hydra.example.com/job/foo/staging/bar";
#             hail-services = "https://hydra.example.com/job/infra/staging/foo-bar-box";
#           };
#       }
# On first init, if you don't already have a 'hail-hail-services' service
# that points to https://hydra.example.com/job/infra/staging/foo-bar-box,
# you will need to manually pull down a build of that job and run the
# 'activate' script.
#
# Then, your box will always have the 'staging' versions of foo and bar
# running, at least until you update your 'foo-bar-box' job to change
# the service set.
let pkgs = import <nixpkgs> {};
in
  { writeScriptBin ? pkgs.writeScriptBin
  , writeTextDir ? pkgs.writeTextDir
  , hail ? null # : Nullable Package
                # ^ The package containing the 'hail' program, or
                # 'null' to use the hail program this nix expression
                # is distributed with
  , nix ? pkgs.nix
  , bash ? pkgs.bash
  , coreutils ? pkgs.coreutils
  , systemd ? pkgs.systemd
  , runCommand ? pkgs.runCommand
  , setupSystemdUnits ? pkgs.setupSystemdUnits
  , lib ? pkgs.lib
  }:
    { services                             # : AttrSet String (Either URI { job-uri     : URI
                                           #                              , netrc-file  : Optional Path
                                           #                              , poll-period : Optional Int
                                           #                              })
                                           # ^ A set whose names are
                                           # profile names and values
                                           # are either a set of hail
                                           # options (see README.md
                                           # for semantics and
                                           # defaults) or hydra job
                                           # URIs
    , target ? "multi-user"                # : String
                                           # ^ The systemd target that
                                           # the hail services should
                                           # be Wanted-By, or null for
                                           # none.
    , namespace ? "hail-systemd-bootstrap" # : String
                                           # ^ The namespace the
                                           # services managed by hail
                                           # should live in. See the
                                           # analogous argument to
                                           # setupSystemdUnits in
                                           # nixpkgs.
    }:
      let # Haaaaacky
          this-hail-bin =
            if builtins.pathExists ./hail.cabal
              then "${toString ./.}/dist/build/hail/hail"
              else
                let found = lib.locateDominatingFile "bin" ./.;
                in if found == null
                  then throw "Could not find hail executable"
                  else builtins.storePath
                         "${toString found.path}/bin/hail";
          hail-bin = if hail == null
                       then this-hail-bin
                       else "${hail}/bin/hail";
          mk-unit = profile: opts:
            let uri = if builtins.isAttrs opts
                        then opts.job-uri
                        else opts;
                netrc-string = lib.optionalString (opts ? netrc-file)
                                 " --netrc-file ${opts.netrc-file}";
                period-string = lib.optionalString (opts ? poll-period)
                                  " --poll-period ${toString opts.poll-period}";
            in
              writeTextDir "hail-${profile}.service"
                ''
                  [Unit]
                  Description=Hail continuous self-deployment service for ${profile}
                  Wants=network-online.target

                  [Service]
                  Environment="PATH=${nix}/bin"
                  Environment="HOME=/var/lib/empty"
                  ExecStart=@${hail-bin} hail --profile hail-profiles/${profile} --job-uri ${uri}${netrc-string}${period-string}
                '';
          setup-systemd-units = setupSystemdUnits
            { units = lib.mapAttrs' (profile: opts:
                rec { name = "hail-${profile}.service";
                      value =
                        { path = "${mk-unit profile opts}/${name}";
                          wanted-by = if target == null
                                        then []
                                        else [ "${target}.target" ];
                        };
                    }
              ) services;
              inherit namespace;
            };
          activate = writeScriptBin "activate"
            ''
              #!${bash}/bin/bash -e
              # We use systemd-run because the program calling this
              # script may be one of the services being updated.
              exec -a systemd-run ${systemd}/bin/systemd-run \
                --description="Update hail services" \
                ${setup-systemd-units}/bin/setup-systemd-units
            '';
      in runCommand "hail-profile" {} ''
        mkdir -p $out/bin
        ln -sv ${activate}/bin/activate $out/bin
        ln -sv ${hail-bin} $out/bin/hail
        ln -sv ${nix}/bin/nix-env $out/bin/nix-env
      ''