at 25.11-pre 7.5 kB view raw
1{ 2 config, 3 lib, 4 pkgs, 5 ... 6}: 7let 8 cfg = config.services.cloud-init; 9 path = 10 with pkgs; 11 [ 12 cloud-init 13 iproute2 14 nettools 15 openssh 16 shadow 17 util-linux 18 busybox 19 ] 20 ++ lib.optional cfg.btrfs.enable btrfs-progs 21 ++ lib.optional cfg.ext4.enable e2fsprogs 22 ++ lib.optional cfg.xfs.enable xfsprogs 23 ++ cfg.extraPackages; 24 hasFs = fsName: lib.any (fs: fs.fsType == fsName) (lib.attrValues config.fileSystems); 25 settingsFormat = pkgs.formats.yaml { }; 26 cfgfile = settingsFormat.generate "cloud.cfg" cfg.settings; 27in 28{ 29 options = { 30 services.cloud-init = { 31 enable = lib.mkOption { 32 type = lib.types.bool; 33 default = false; 34 description = '' 35 Enable the cloud-init service. This services reads 36 configuration metadata in a cloud environment and configures 37 the machine according to this metadata. 38 39 This configuration is not completely compatible with the 40 NixOS way of doing configuration, as configuration done by 41 cloud-init might be overridden by a subsequent nixos-rebuild 42 call. However, some parts of cloud-init fall outside of 43 NixOS's responsibility, like filesystem resizing and ssh 44 public key provisioning, and cloud-init is useful for that 45 parts. Thus, be wary that using cloud-init in NixOS might 46 come as some cost. 47 ''; 48 }; 49 50 btrfs.enable = lib.mkOption { 51 type = lib.types.bool; 52 default = hasFs "btrfs"; 53 defaultText = lib.literalExpression ''hasFs "btrfs"''; 54 description = '' 55 Allow the cloud-init service to operate `btrfs` filesystem. 56 ''; 57 }; 58 59 ext4.enable = lib.mkOption { 60 type = lib.types.bool; 61 default = hasFs "ext4"; 62 defaultText = lib.literalExpression ''hasFs "ext4"''; 63 description = '' 64 Allow the cloud-init service to operate `ext4` filesystem. 65 ''; 66 }; 67 68 xfs.enable = lib.mkOption { 69 type = lib.types.bool; 70 default = hasFs "xfs"; 71 defaultText = lib.literalExpression ''hasFs "xfs"''; 72 description = '' 73 Allow the cloud-init service to operate `xfs` filesystem. 74 ''; 75 }; 76 77 network.enable = lib.mkOption { 78 type = lib.types.bool; 79 default = false; 80 description = '' 81 Allow the cloud-init service to configure network interfaces 82 through systemd-networkd. 83 ''; 84 }; 85 86 extraPackages = lib.mkOption { 87 type = lib.types.listOf lib.types.package; 88 default = [ ]; 89 description = '' 90 List of additional packages to be available within cloud-init jobs. 91 ''; 92 }; 93 94 settings = lib.mkOption { 95 description = '' 96 Structured cloud-init configuration. 97 ''; 98 type = lib.types.submodule { 99 freeformType = settingsFormat.type; 100 }; 101 default = { }; 102 }; 103 104 config = lib.mkOption { 105 type = lib.types.str; 106 default = ""; 107 description = '' 108 raw cloud-init configuration. 109 110 Takes precedence over the `settings` option if set. 111 ''; 112 }; 113 114 }; 115 116 }; 117 118 config = lib.mkIf cfg.enable { 119 services.cloud-init.settings = { 120 system_info = lib.mkDefault { 121 distro = "nixos"; 122 network = { 123 renderers = [ "networkd" ]; 124 }; 125 }; 126 127 users = lib.mkDefault [ "root" ]; 128 disable_root = lib.mkDefault false; 129 preserve_hostname = lib.mkDefault false; 130 131 cloud_init_modules = lib.mkDefault [ 132 "migrator" 133 "seed_random" 134 "bootcmd" 135 "write-files" 136 "growpart" 137 "resizefs" 138 "update_hostname" 139 "resolv_conf" 140 "ca-certs" 141 "rsyslog" 142 "users-groups" 143 ]; 144 145 cloud_config_modules = lib.mkDefault [ 146 "disk_setup" 147 "mounts" 148 "ssh-import-id" 149 "set-passwords" 150 "timezone" 151 "disable-ec2-metadata" 152 "runcmd" 153 "ssh" 154 ]; 155 156 cloud_final_modules = lib.mkDefault [ 157 "rightscale_userdata" 158 "scripts-vendor" 159 "scripts-per-once" 160 "scripts-per-boot" 161 "scripts-per-instance" 162 "scripts-user" 163 "ssh-authkey-fingerprints" 164 "keys-to-console" 165 "phone-home" 166 "final-message" 167 "power-state-change" 168 ]; 169 }; 170 171 environment.etc."cloud/cloud.cfg" = 172 if cfg.config == "" then { source = cfgfile; } else { text = cfg.config; }; 173 174 systemd.network.enable = lib.mkIf cfg.network.enable true; 175 176 systemd.services.cloud-init-local = { 177 description = "Initial cloud-init job (pre-networking)"; 178 wantedBy = [ "multi-user.target" ]; 179 # In certain environments (AWS for example), cloud-init-local will 180 # first configure an IP through DHCP, and later delete it. 181 # This can cause race conditions with anything else trying to set IP through DHCP. 182 before = [ 183 "systemd-networkd.service" 184 "dhcpcd.service" 185 ]; 186 path = path; 187 serviceConfig = { 188 Type = "oneshot"; 189 ExecStart = "${pkgs.cloud-init}/bin/cloud-init init --local"; 190 RemainAfterExit = "yes"; 191 TimeoutSec = "infinity"; 192 StandardOutput = "journal+console"; 193 }; 194 }; 195 196 systemd.services.cloud-init = { 197 description = "Initial cloud-init job (metadata service crawler)"; 198 wantedBy = [ "multi-user.target" ]; 199 wants = [ 200 "network-online.target" 201 "cloud-init-local.service" 202 "sshd.service" 203 "sshd-keygen.service" 204 ]; 205 after = [ 206 "network-online.target" 207 "cloud-init-local.service" 208 ]; 209 before = [ 210 "sshd.service" 211 "sshd-keygen.service" 212 ]; 213 requires = [ "network.target" ]; 214 path = path; 215 serviceConfig = { 216 Type = "oneshot"; 217 ExecStart = "${pkgs.cloud-init}/bin/cloud-init init"; 218 RemainAfterExit = "yes"; 219 TimeoutSec = "infinity"; 220 StandardOutput = "journal+console"; 221 }; 222 }; 223 224 systemd.services.cloud-config = { 225 description = "Apply the settings specified in cloud-config"; 226 wantedBy = [ "multi-user.target" ]; 227 wants = [ "network-online.target" ]; 228 after = [ 229 "network-online.target" 230 "cloud-config.target" 231 ]; 232 233 path = path; 234 serviceConfig = { 235 Type = "oneshot"; 236 ExecStart = "${pkgs.cloud-init}/bin/cloud-init modules --mode=config"; 237 RemainAfterExit = "yes"; 238 TimeoutSec = "infinity"; 239 StandardOutput = "journal+console"; 240 }; 241 }; 242 243 systemd.services.cloud-final = { 244 description = "Execute cloud user/final scripts"; 245 wantedBy = [ "multi-user.target" ]; 246 wants = [ "network-online.target" ]; 247 after = [ 248 "network-online.target" 249 "cloud-config.service" 250 "rc-local.service" 251 ]; 252 requires = [ "cloud-config.target" ]; 253 path = path; 254 serviceConfig = { 255 Type = "oneshot"; 256 ExecStart = "${pkgs.cloud-init}/bin/cloud-init modules --mode=final"; 257 RemainAfterExit = "yes"; 258 TimeoutSec = "infinity"; 259 StandardOutput = "journal+console"; 260 }; 261 }; 262 263 systemd.targets.cloud-config = { 264 description = "Cloud-config availability"; 265 requires = [ 266 "cloud-init-local.service" 267 "cloud-init.service" 268 ]; 269 }; 270 }; 271 272 meta.maintainers = [ lib.maintainers.zimbatm ]; 273}