diff --git a/doc/start/iso.md b/doc/start/iso.md index 76af1c6ef..3aa5e55b7 100644 --- a/doc/start/iso.md +++ b/doc/start/iso.md @@ -1,9 +1,12 @@ # ISO -Making and writing an installable iso for `hosts/bootstrap.nix` is as simple as: +Making and writing an installable iso for a host is as simple as +entering the devshell and running `boostrap-iso burn `. For instance, to +burn an iso for the host defined in `hosts/bootstrap.nix`, run: + ```sh -bud build bootstrap bootstrapIso -sudo -E $(which bud) burn +nix develop +bootstrap-iso burn bootstrap # note: uses sudo ``` This works for any host. diff --git a/examples/devos/flake.nix b/examples/devos/flake.nix index 82de770b6..f259544f6 100644 --- a/examples/devos/flake.nix +++ b/examples/devos/flake.nix @@ -11,7 +11,8 @@ nixos.url = "github:nixos/nixpkgs/nixos-21.11"; latest.url = "github:nixos/nixpkgs/nixos-unstable"; - digga.url = "github:divnix/digga"; + #digga.url = "github:divnix/digga"; + digga.url = "path:/home/matt/git/packaging/nix/digga"; digga.inputs.nixpkgs.follows = "nixos"; digga.inputs.nixlib.follows = "nixos"; digga.inputs.home-manager.follows = "home"; diff --git a/examples/devos/hosts/bootstrap.nix b/examples/devos/hosts/bootstrap.nix index d491855d6..0d413f8f5 100644 --- a/examples/devos/hosts/bootstrap.nix +++ b/examples/devos/hosts/bootstrap.nix @@ -1,6 +1,15 @@ { profiles, ... }: { - # build with: `bud build bootstrap bootstrapIso` + # build (from within a devshell) with: + # + # nixos-generate --format bootstrap-iso --flake '.#bootstrap' + # + # or: + # + # bootstrap-iso build bootstrap + # + # which does the same thing. + # # reachable on the local link via ssh root@fe80::47%eno1 # where 'eno1' is replaced by your own machine's network # interface that has the local link to the target machine @@ -13,6 +22,7 @@ boot.loader.systemd-boot.enable = true; - # will be overridden by the bootstrapIso instrumentation + # will be overridden by the bootstrap-iso `nixos-generate` format profile + # defined by the digga "nixos-generators" devshell module fileSystems."/" = { device = "/dev/disk/by-label/nixos"; }; } diff --git a/examples/devos/shell/default.nix b/examples/devos/shell/default.nix index d22b3af43..35a4d8f37 100644 --- a/examples/devos/shell/default.nix +++ b/examples/devos/shell/default.nix @@ -2,6 +2,7 @@ { modules = with inputs; [ bud.devshellModules.bud + digga.devshellModules.nixos-generators ]; exportedModules = [ ./devos.nix diff --git a/examples/devos/shell/devos.nix b/examples/devos/shell/devos.nix index 581aee9a7..6b74e5fda 100644 --- a/examples/devos/shell/devos.nix +++ b/examples/devos/shell/devos.nix @@ -48,8 +48,14 @@ in ++ lib.optional (system != "i686-linux") (devos cachix) - ++ lib.optional - (system != "aarch64-darwin") - (devos inputs.nixos-generators.defaultPackage.${pkgs.system}) ; + + # digga-supplied extensions to nixos-generators. Provides the + # "bootstrap-iso" nixos-generators format, plus the "bootstrap-iso" wrapper + # command. + digga.nixos-generators = { + enable = pkgs.system != "aarch64-darwin"; + category = "devos"; + package = inputs.nixos-generators.defaultPackage.${pkgs.system}; + }; } diff --git a/flake.nix b/flake.nix index f3c32b947..e7389ee1d 100644 --- a/flake.nix +++ b/flake.nix @@ -116,7 +116,8 @@ # a little extra service ... overlays = import ./overlays { inherit inputs; }; - nixosModules = import ./modules; + nixosModules = import ./modules/nixos; + devshellModules = import ./modules/devShell; defaultTemplate = self.templates.devos; templates.devos.path = ./examples/devos; diff --git a/modules/bootstrap-iso.nix b/modules/bootstrap-iso.nix deleted file mode 100644 index d7a11ca38..000000000 --- a/modules/bootstrap-iso.nix +++ /dev/null @@ -1,74 +0,0 @@ -let - getFqdn = config: - let - net = config.networking; - fqdn = - if net.domain != null - then "${net.hostName}.${net.domain}" - else net.hostName; - in - fqdn; - - protoModule = fullHostConfig: { config, lib, modulesPath, suites, self, inputs, ... }@args: { - - imports = [ "${modulesPath}/installer/cd-dvd/installation-cd-minimal.nix" ]; - - isoImage.isoBaseName = "bootstrap-" + (getFqdn config); - isoImage.contents = [{ - source = self; - target = "/devos/"; - }]; - isoImage.storeContents = [ - self.devShell.${config.nixpkgs.system} - # include also closures that are "switched off" by the - # above profile filter on the local config attribute - fullHostConfig.system.build.toplevel - ] ++ builtins.attrValues inputs; - # still pull in tools of deactivated profiles - environment.systemPackages = fullHostConfig.environment.systemPackages; - - # confilcts with networking.wireless which might be slightly - # more useful on a stick - networking.networkmanager.enable = lib.mkForce false; - # confilcts with networking.wireless - networking.wireless.iwd.enable = lib.mkForce false; - - # Set up a link-local boostrap network - # See also: https://github.com/NixOS/nixpkgs/issues/75515#issuecomment-571661659 - networking.usePredictableInterfaceNames = lib.mkForce true; # so prefix matching works - networking.useNetworkd = lib.mkForce true; - networking.useDHCP = lib.mkForce false; - networking.dhcpcd.enable = lib.mkForce false; - systemd.network = { - # https://www.freedesktop.org/software/systemd/man/systemd.network.html - networks."boostrap-link-local" = { - matchConfig = { - Name = "en* wl* ww*"; - }; - networkConfig = { - Description = "Link-local host bootstrap network"; - MulticastDNS = true; - LinkLocalAddressing = "ipv6"; - DHCP = "yes"; - }; - address = [ - # fall back well-known link-local for situations where MulticastDNS is not available - "fe80::47" # 47: n=14 i=9 x=24; n+i+x - ]; - extraConfig = '' - # Unique, yet stable. Based off the MAC address. - IPv6LinkLocalAddressGenerationMode = "eui64" - ''; - }; - }; - }; -in -{ config, ... }: -{ - system.build = { - bootstrapIso = (config.lib.digga.mkBuild - (protoModule config) - ).config.system.build.isoImage; - }; -} - diff --git a/modules/default.nix b/modules/default.nix deleted file mode 100644 index 33403434a..000000000 --- a/modules/default.nix +++ /dev/null @@ -1,4 +0,0 @@ -{ - nixConfig = import ./nix-config.nix; - bootstrapIso = import ./bootstrap-iso.nix; -} diff --git a/modules/devShell/default.nix b/modules/devShell/default.nix new file mode 100644 index 000000000..e4e716a1d --- /dev/null +++ b/modules/devShell/default.nix @@ -0,0 +1,3 @@ +{ + nixos-generators = import ./nixos-generators; +} diff --git a/modules/devShell/nixos-generators/bootstrap-iso b/modules/devShell/nixos-generators/bootstrap-iso new file mode 100755 index 000000000..edeb2daf7 --- /dev/null +++ b/modules/devShell/nixos-generators/bootstrap-iso @@ -0,0 +1,64 @@ +#!/bin/sh + +set -eu + +if [ -z "${PRJ_ROOT:-}" ]; then + if ! PRJ_ROOT="$(git rev-parse --show-toplevel 2>/dev/null)"; then + # shellcheck disable=SC2016 + printf 1>&2 -- '%s: %s. %s. %s.\n' \ + "${0##*/}" 'unable to locate your project root ($PRJ_ROOT)' \ + 'bud relies on the project root for locating the bootstrap ISO' \ + 'Aborting' + + exit 1 + fi +fi + +boostrapIsoRequireHost() { + if [ "$#" -lt 1 ]; then + printf 1>&2 -- 'Error: missing required argument.\n' "${0##*/}" + bootstrapIsoHelp 1 + fi +} + +bootstrapIsoBuild() { + boostrapIsoRequireHost "$@" || return + + local host="$1" + shift + + # XXX the way nixos-generate handles flake specifications requires that we do + # not quote the host as we would with, e.g.: + # nix build ".#nixosConfigurations.\"my.host.name\".config.system.build.toplevel" + nixos-generate "$@" --format bootstrap-iso --flake "${PRJ_ROOT}#${host}" +} + +bootstrapIsoBurn() { + boostrapIsoRequireHost "$@" || return + bud="$(command -v bud)" || return + bootstrapIsoBuild "$@" --out-link "${PRJ_ROOT?}/result" || return + sudo -E "$bud" burn +} + +bootstrapIsoHelp() { + printf 1>&2 -- 'Usage: %s {build,burn,help} [ ...]\n' "${0##*/}" + return "${1:-0}" +} + +cmd="${1:-}" +shift 2>/dev/null || : + +case "$cmd" in + build) + bootstrapIsoBuild "$@" + ;; + burn) + bootstrapIsoBurn "$@" + ;; + help) + bootstrapIsoHelp + ;; + *) + bootstrapIsoHelp 1 + ;; +esac diff --git a/modules/devShell/nixos-generators/default.nix b/modules/devShell/nixos-generators/default.nix new file mode 100644 index 000000000..200c64ce3 --- /dev/null +++ b/modules/devShell/nixos-generators/default.nix @@ -0,0 +1,53 @@ +{ config, lib, pkgs, ... }: + +let + cfg = config.digga.nixos-generators; + + searchPathVar = "NIXOS_GENERATORS_FORMAT_SEARCH_PATH"; + + bootstrap-iso = { + category = "devos"; + name = "bootstrap-iso"; + help = "Create and burn a bootstrap ISO for the specified NixOS configuration"; + command = builtins.readFile ./bootstrap-iso; + }; +in +{ + options.digga.nixos-generators = + let + inherit (lib) mkOption mkEnableOption types; + in + { + enable = mkEnableOption "nixos-generators extensions"; + + category = mkOption { + type = types.str; + default = "generators"; + description = "category for the nixos-generate and bootstrap-iso commands"; + }; + + package = mkOption { + type = types.package; + default = pkgs.nixos-generators; + description = "package providing nixos-generators"; + }; + }; + + config = lib.mkIf cfg.enable { + commands = [ + { inherit (cfg) category package; } + bootstrap-iso + ]; + + env = [ + { + name = searchPathVar; + + # prepend our formats directory to the nixos-generate search path + eval = '' + ''${${searchPathVar}:+''${${searchPathVar}}:}${toString ./formats} + ''; + } + ]; + }; +} diff --git a/modules/devShell/nixos-generators/formats/bootstrap-iso.nix b/modules/devShell/nixos-generators/formats/bootstrap-iso.nix new file mode 100644 index 000000000..f62b222be --- /dev/null +++ b/modules/devShell/nixos-generators/formats/bootstrap-iso.nix @@ -0,0 +1,68 @@ +let + getFqdn = config: + let + net = config.networking; + fqdn = + if net.domain != null + then "${net.hostName}.${net.domain}" + else net.hostName; + in + fqdn; +in + +{ config, lib, modulesPath, suites, self, inputs, ... }@args: { + + imports = [ "${modulesPath}/installer/cd-dvd/installation-cd-minimal.nix" ]; + + isoImage.isoBaseName = "bootstrap-" + (getFqdn config); + isoImage.contents = [{ + source = self; + target = "/devos/"; + }]; + isoImage.storeContents = [ + self.devShell.${config.nixpkgs.system} + # include also closures that are "switched off" by the + # above profile filter on the local config attribute + config.system.build.toplevel + ] ++ builtins.attrValues inputs; + + # confilcts with networking.wireless which might be slightly + # more useful on a stick + networking.networkmanager.enable = lib.mkForce false; + # confilcts with networking.wireless + networking.wireless.iwd.enable = lib.mkForce false; + + # Set up a link-local boostrap network + # See also: https://github.com/NixOS/nixpkgs/issues/75515#issuecomment-571661659 + networking.usePredictableInterfaceNames = lib.mkForce true; # so prefix matching works + networking.useNetworkd = lib.mkForce true; + networking.useDHCP = lib.mkForce false; + networking.dhcpcd.enable = lib.mkForce false; + systemd.network = { + # https://www.freedesktop.org/software/systemd/man/systemd.network.html + networks."boostrap-link-local" = { + matchConfig = { + Name = "en* wl* ww*"; + }; + networkConfig = { + Description = "Link-local host bootstrap network"; + MulticastDNS = true; + LinkLocalAddressing = "ipv6"; + DHCP = "yes"; + }; + address = [ + # fall back well-known link-local for situations where MulticastDNS is not available + "fe80::47" # 47: n=14 i=9 x=24; n+i+x + ]; + extraConfig = '' + # Unique, yet stable. Based off the MAC address. + IPv6LinkLocalAddressGenerationMode = "eui64" + ''; + }; + }; + + # Required by nixos-generate + formatAttr = "isoImage"; + filename = "*.iso"; +} + diff --git a/modules/nixos/default.nix b/modules/nixos/default.nix new file mode 100644 index 000000000..1c779276c --- /dev/null +++ b/modules/nixos/default.nix @@ -0,0 +1,3 @@ +{ + nixConfig = import ./nix-config.nix; +} diff --git a/modules/nix-config.nix b/modules/nixos/nix-config.nix similarity index 100% rename from modules/nix-config.nix rename to modules/nixos/nix-config.nix