1{ config, pkgs, lib, ... }:
2with lib;
3let
4 cfg = config.virtualisation.digitalOcean;
5 defaultConfigFile = pkgs.writeText "digitalocean-configuration.nix" ''
6 { modulesPath, lib, ... }:
7 {
8 imports = lib.optional (builtins.pathExists ./do-userdata.nix) ./do-userdata.nix ++ [
9 (modulesPath + "/virtualisation/digital-ocean-config.nix")
10 ];
11 }
12 '';
13in {
14 options.virtualisation.digitalOcean.rebuildFromUserData = mkOption {
15 type = types.bool;
16 default = true;
17 example = true;
18 description = lib.mdDoc "Whether to reconfigure the system from Digital Ocean user data";
19 };
20 options.virtualisation.digitalOcean.defaultConfigFile = mkOption {
21 type = types.path;
22 default = defaultConfigFile;
23 defaultText = literalMD ''
24 The default configuration imports user-data if applicable and
25 `(modulesPath + "/virtualisation/digital-ocean-config.nix")`.
26 '';
27 description = lib.mdDoc ''
28 A path to a configuration file which will be placed at
29 `/etc/nixos/configuration.nix` and be used when switching to
30 a new configuration.
31 '';
32 };
33
34 config = {
35 systemd.services.digitalocean-init = mkIf cfg.rebuildFromUserData {
36 description = "Reconfigure the system from Digital Ocean userdata on startup";
37 wantedBy = [ "network-online.target" ];
38 unitConfig = {
39 ConditionPathExists = "!/etc/nixos/do-userdata.nix";
40 After = [ "digitalocean-metadata.service" "network-online.target" ];
41 Requires = [ "digitalocean-metadata.service" ];
42 X-StopOnRemoval = false;
43 };
44 serviceConfig = {
45 Type = "oneshot";
46 RemainAfterExit = true;
47 };
48 restartIfChanged = false;
49 path = [ pkgs.jq pkgs.gnused pkgs.gnugrep config.systemd.package config.nix.package config.system.build.nixos-rebuild ];
50 environment = {
51 HOME = "/root";
52 NIX_PATH = concatStringsSep ":" [
53 "/nix/var/nix/profiles/per-user/root/channels/nixos"
54 "nixos-config=/etc/nixos/configuration.nix"
55 "/nix/var/nix/profiles/per-user/root/channels"
56 ];
57 };
58 script = ''
59 set -e
60 echo "attempting to fetch configuration from Digital Ocean user data..."
61 userData=$(mktemp)
62 if jq -er '.user_data' /run/do-metadata/v1.json > $userData; then
63 # If the user-data looks like it could be a nix expression,
64 # copy it over. Also, look for a magic three-hash comment and set
65 # that as the channel.
66 if nix-instantiate --parse $userData > /dev/null; then
67 channels="$(grep '^###' "$userData" | sed 's|###\s*||')"
68 printf "%s" "$channels" | while read channel; do
69 echo "writing channel: $channel"
70 done
71
72 if [[ -n "$channels" ]]; then
73 printf "%s" "$channels" > /root/.nix-channels
74 nix-channel --update
75 fi
76
77 echo "setting configuration from Digital Ocean user data"
78 cp "$userData" /etc/nixos/do-userdata.nix
79 if [[ ! -e /etc/nixos/configuration.nix ]]; then
80 install -m0644 ${cfg.defaultConfigFile} /etc/nixos/configuration.nix
81 fi
82 else
83 echo "user data does not appear to be a Nix expression; ignoring"
84 exit
85 fi
86
87 nixos-rebuild switch
88 else
89 echo "no user data is available"
90 fi
91 '';
92 };
93 };
94 meta.maintainers = with maintainers; [ arianvp eamsden ];
95}