at 23.11-pre 7.3 kB view raw
1{ lib, config, pkgs, ... }: 2 3with lib; 4 5let 6 templateSubmodule = { ... }: { 7 options = { 8 enable = mkEnableOption (lib.mdDoc "this template"); 9 10 target = mkOption { 11 description = lib.mdDoc "Path in the container"; 12 type = types.path; 13 }; 14 template = mkOption { 15 description = lib.mdDoc ".tpl file for rendering the target"; 16 type = types.path; 17 }; 18 when = mkOption { 19 description = lib.mdDoc "Events which trigger a rewrite (create, copy)"; 20 type = types.listOf (types.str); 21 }; 22 properties = mkOption { 23 description = lib.mdDoc "Additional properties"; 24 type = types.attrs; 25 default = {}; 26 }; 27 }; 28 }; 29 30 toYAML = name: data: pkgs.writeText name (generators.toYAML {} data); 31 32 cfg = config.virtualisation.lxc; 33 templates = if cfg.templates != {} then let 34 list = mapAttrsToList (name: value: { inherit name; } // value) 35 (filterAttrs (name: value: value.enable) cfg.templates); 36 in 37 { 38 files = map (tpl: { 39 source = tpl.template; 40 target = "/templates/${tpl.name}.tpl"; 41 }) list; 42 properties = listToAttrs (map (tpl: nameValuePair tpl.target { 43 when = tpl.when; 44 template = "${tpl.name}.tpl"; 45 properties = tpl.properties; 46 }) list); 47 } 48 else { files = []; properties = {}; }; 49 50in 51{ 52 imports = [ 53 ../installer/cd-dvd/channel.nix 54 ../profiles/clone-config.nix 55 ../profiles/minimal.nix 56 ]; 57 58 options = { 59 virtualisation.lxc = { 60 templates = mkOption { 61 description = lib.mdDoc "Templates for LXD"; 62 type = types.attrsOf (types.submodule (templateSubmodule)); 63 default = {}; 64 example = literalExpression '' 65 { 66 # create /etc/hostname on container creation. also requires networking.hostName = "" to be set 67 "hostname" = { 68 enable = true; 69 target = "/etc/hostname"; 70 template = builtins.toFile "hostname.tpl" "{{ container.name }}"; 71 when = [ "create" ]; 72 }; 73 # create /etc/nixos/hostname.nix with a configuration for keeping the hostname applied 74 "hostname-nix" = { 75 enable = true; 76 target = "/etc/nixos/hostname.nix"; 77 template = builtins.toFile "hostname-nix.tpl" "{ ... }: { networking.hostName = \"{{ container.name }}\"; }"; 78 # copy keeps the file updated when the container is changed 79 when = [ "create" "copy" ]; 80 }; 81 # copy allow the user to specify a custom configuration.nix 82 "configuration-nix" = { 83 enable = true; 84 target = "/etc/nixos/configuration.nix"; 85 template = builtins.toFile "configuration-nix" "{{ config_get(\"user.user-data\", properties.default) }}"; 86 when = [ "create" ]; 87 }; 88 }; 89 ''; 90 }; 91 92 privilegedContainer = mkOption { 93 type = types.bool; 94 default = false; 95 description = lib.mdDoc '' 96 Whether this LXC container will be running as a privileged container or not. If set to `true` then 97 additional configuration will be applied to the `systemd` instance running within the container as 98 recommended by [distrobuilder](https://linuxcontainers.org/distrobuilder/introduction/). 99 ''; 100 }; 101 }; 102 }; 103 104 config = { 105 boot.isContainer = true; 106 boot.postBootCommands = 107 '' 108 # After booting, register the contents of the Nix store in the Nix 109 # database. 110 if [ -f /nix-path-registration ]; then 111 ${config.nix.package.out}/bin/nix-store --load-db < /nix-path-registration && 112 rm /nix-path-registration 113 fi 114 115 # nixos-rebuild also requires a "system" profile 116 ${config.nix.package.out}/bin/nix-env -p /nix/var/nix/profiles/system --set /run/current-system 117 ''; 118 119 system.build.metadata = pkgs.callPackage ../../lib/make-system-tarball.nix { 120 contents = [ 121 { 122 source = toYAML "metadata.yaml" { 123 architecture = builtins.elemAt (builtins.match "^([a-z0-9_]+).+" (toString pkgs.system)) 0; 124 creation_date = 1; 125 properties = { 126 description = "${config.system.nixos.distroName} ${config.system.nixos.codeName} ${config.system.nixos.label} ${pkgs.system}"; 127 os = "${config.system.nixos.distroId}"; 128 release = "${config.system.nixos.codeName}"; 129 }; 130 templates = templates.properties; 131 }; 132 target = "/metadata.yaml"; 133 } 134 ] ++ templates.files; 135 }; 136 137 # TODO: build rootfs as squashfs for faster unpack 138 system.build.tarball = pkgs.callPackage ../../lib/make-system-tarball.nix { 139 extraArgs = "--owner=0"; 140 141 storeContents = [ 142 { 143 object = config.system.build.toplevel; 144 symlink = "none"; 145 } 146 ]; 147 148 contents = [ 149 { 150 source = config.system.build.toplevel + "/init"; 151 target = "/sbin/init"; 152 } 153 # Technically this is not required for lxc, but having also make this configuration work with systemd-nspawn. 154 # Nixos will setup the same symlink after start. 155 { 156 source = config.system.build.toplevel + "/etc/os-release"; 157 target = "/etc/os-release"; 158 } 159 ]; 160 161 extraCommands = "mkdir -p proc sys dev"; 162 }; 163 164 system.build.installBootLoader = pkgs.writeScript "install-lxd-sbin-init.sh" '' 165 #!${pkgs.runtimeShell} 166 ln -fs "$1/init" /sbin/init 167 ''; 168 169 # Add the overrides from lxd distrobuilder 170 # https://github.com/lxc/distrobuilder/blob/05978d0d5a72718154f1525c7d043e090ba7c3e0/distrobuilder/main.go#L630 171 systemd.packages = [ 172 (pkgs.writeTextFile { 173 name = "systemd-lxc-service-overrides"; 174 destination = "/etc/systemd/system/service.d/zzz-lxc-service.conf"; 175 text = '' 176 [Service] 177 ProcSubset=all 178 ProtectProc=default 179 ProtectControlGroups=no 180 ProtectKernelTunables=no 181 NoNewPrivileges=no 182 LoadCredential= 183 '' + optionalString cfg.privilegedContainer '' 184 # Additional settings for privileged containers 185 ProtectHome=no 186 ProtectSystem=no 187 PrivateDevices=no 188 PrivateTmp=no 189 ProtectKernelLogs=no 190 ProtectKernelModules=no 191 ReadWritePaths= 192 ''; 193 }) 194 ]; 195 196 # Allow the user to login as root without password. 197 users.users.root.initialHashedPassword = mkOverride 150 ""; 198 199 system.activationScripts.installInitScript = mkForce '' 200 ln -fs $systemConfig/init /sbin/init 201 ''; 202 203 # Some more help text. 204 services.getty.helpLine = 205 '' 206 207 Log in as "root" with an empty password. 208 ''; 209 210 # Containers should be light-weight, so start sshd on demand. 211 services.openssh.enable = mkDefault true; 212 services.openssh.startWhenNeeded = mkDefault true; 213 214 # As this is intended as a standalone image, undo some of the minimal profile stuff 215 environment.noXlibs = false; 216 documentation.enable = true; 217 documentation.nixos.enable = true; 218 services.logrotate.enable = true; 219 }; 220}