1{ config, lib, pkgs, ... }:
2
3with lib;
4
5let cfg = config.services.cloud-init;
6 path = with pkgs; [ cloud-init nettools utillinux e2fsprogs shadow openssh iproute ];
7in
8{
9 options = {
10
11 services.cloud-init = {
12
13 enable = mkOption {
14 type = types.bool;
15 default = false;
16 description = ''
17 Enable the cloud-init service. This services reads
18 configuration metadata in a cloud environment and configures
19 the machine according to this metadata.
20
21 This configuration is not completely compatible with the
22 NixOS way of doing configuration, as configuration done by
23 cloud-init might be overriden by a subsequent nixos-rebuild
24 call. However, some parts of cloud-init fall outside of
25 NixOS's responsibility, like filesystem resizing and ssh
26 public key provisioning, and cloud-init is useful for that
27 parts. Thus, be wary that using cloud-init in NixOS might
28 come as some cost.
29 '';
30 };
31
32 config = mkOption {
33 type = types.str;
34 default = ''
35 system_info:
36 distro: nixos
37 users:
38 - root
39
40 disable_root: false
41 preserve_hostname: false
42
43 cloud_init_modules:
44 - migrator
45 - seed_random
46 - bootcmd
47 - write-files
48 - growpart
49 - resizefs
50 - update_etc_hosts
51 - ca-certs
52 - rsyslog
53 - users-groups
54
55 cloud_config_modules:
56 - disk_setup
57 - mounts
58 - ssh-import-id
59 - set-passwords
60 - timezone
61 - disable-ec2-metadata
62 - runcmd
63 - ssh
64
65 cloud_final_modules:
66 - rightscale_userdata
67 - scripts-vendor
68 - scripts-per-once
69 - scripts-per-boot
70 - scripts-per-instance
71 - scripts-user
72 - ssh-authkey-fingerprints
73 - keys-to-console
74 - phone-home
75 - final-message
76 - power-state-change
77 '';
78 description = ''cloud-init configuration.'';
79 };
80
81 };
82
83 };
84
85 config = mkIf cfg.enable {
86
87 environment.etc."cloud/cloud.cfg".text = cfg.config;
88
89 systemd.services.cloud-init-local =
90 { description = "Initial cloud-init job (pre-networking)";
91 wantedBy = [ "multi-user.target" ];
92 wants = [ "local-fs.target" ];
93 after = [ "local-fs.target" ];
94 path = path;
95 serviceConfig =
96 { Type = "oneshot";
97 ExecStart = "${pkgs.cloud-init}/bin/cloud-init init --local";
98 RemainAfterExit = "yes";
99 TimeoutSec = "0";
100 StandardOutput = "journal+console";
101 };
102 };
103
104 systemd.services.cloud-init =
105 { description = "Initial cloud-init job (metadata service crawler)";
106 wantedBy = [ "multi-user.target" ];
107 wants = [ "local-fs.target" "network-online.target" "cloud-init-local.service"
108 "sshd.service" "sshd-keygen.service" ];
109 after = [ "local-fs.target" "network-online.target" "cloud-init-local.service" ];
110 before = [ "sshd.service" "sshd-keygen.service" ];
111 requires = [ "network.target "];
112 path = path;
113 serviceConfig =
114 { Type = "oneshot";
115 ExecStart = "${pkgs.cloud-init}/bin/cloud-init init";
116 RemainAfterExit = "yes";
117 TimeoutSec = "0";
118 StandardOutput = "journal+console";
119 };
120 };
121
122 systemd.services.cloud-config =
123 { description = "Apply the settings specified in cloud-config";
124 wantedBy = [ "multi-user.target" ];
125 wants = [ "network-online.target" ];
126 after = [ "network-online.target" "syslog.target" "cloud-config.target" ];
127
128 path = path;
129 serviceConfig =
130 { Type = "oneshot";
131 ExecStart = "${pkgs.cloud-init}/bin/cloud-init modules --mode=config";
132 RemainAfterExit = "yes";
133 TimeoutSec = "0";
134 StandardOutput = "journal+console";
135 };
136 };
137
138 systemd.services.cloud-final =
139 { description = "Execute cloud user/final scripts";
140 wantedBy = [ "multi-user.target" ];
141 wants = [ "network-online.target" ];
142 after = [ "network-online.target" "syslog.target" "cloud-config.service" "rc-local.service" ];
143 requires = [ "cloud-config.target" ];
144 path = path;
145 serviceConfig =
146 { Type = "oneshot";
147 ExecStart = "${pkgs.cloud-init}/bin/cloud-init modules --mode=final";
148 RemainAfterExit = "yes";
149 TimeoutSec = "0";
150 StandardOutput = "journal+console";
151 };
152 };
153
154 systemd.targets.cloud-config =
155 { description = "Cloud-config availability";
156 requires = [ "cloud-init-local.service" "cloud-init.service" ];
157 };
158 };
159}