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