From 6de67fc2040a8ab74a2225376869b024175c2f0b Mon Sep 17 00:00:00 2001
From: Jens Nolte <git@queezle.net>
Date: Sun, 20 Dec 2020 03:28:30 +0100
Subject: [PATCH] Use nix flake support to build and deploy machines

---
 bin/deploy                          |  32 ++++----
 channels/nixos-19.09/default.nix    |   1 -
 channels/nixos-unstable/default.nix |   1 -
 configuration.nix                   |  42 ++++++----
 flake.lock                          |   6 +-
 layers/workstation.nix              |   1 +
 layers/zsh.nix                      |   4 +-
 machine-manager.nix                 | 122 +++++++++++++++++-----------
 8 files changed, 119 insertions(+), 90 deletions(-)

diff --git a/bin/deploy b/bin/deploy
index a78c412..051fccc 100755
--- a/bin/deploy
+++ b/bin/deploy
@@ -8,7 +8,7 @@ set -o pipefail
 readonly cmdname=$(basename $0)
 
 
-readonly machines_repo_entry_point=$MACHINES_PATH/default.nix
+readonly machines_repo_entry_point=$MACHINES_PATH/flake.nix
 
 # This script cannot run without the nixos configuration entry point
 if [[ ! -f "$machines_repo_entry_point" ]]
@@ -17,7 +17,6 @@ then
   exit 2
 fi
 
-
 source $DOTFILES_PATH/bin/lib/util.zsh
 
 usage() {
@@ -101,7 +100,7 @@ trap "rm -rf $local_temp_dir" EXIT INT HUP TERM
 if [[ "$operation" = "iso" ]]
 then
   print_info "Building iso image"
-  nix build --file "$MACHINES_PATH" --out-link "$local_temp_dir/nixos-iso-$hostname" "nixosIsoDerivations.$hostname"
+  nix build "path:$MACHINES_PATH#nixosConfigurations.$hostname.config.system.build.iso" --out-link "$local_temp_dir/nixos-iso-$hostname"
   readonly nixos_iso_path=$(realpath "$local_temp_dir/nixos-iso-$hostname")
 
   print_info "Iso generated"
@@ -110,22 +109,22 @@ then
 fi
 
 
-print_info "Building target system configuration"
-nix build --file "$MACHINES_PATH" --out-link "$local_temp_dir/nixos-config-$hostname" "nixosSystemDerivations.$hostname"
-readonly nixos_config_path=$(realpath "$local_temp_dir/nixos-config-$hostname")
-
-if [[ "$operation" = "build" ]]
-then
-  print_info "Build completed"
-  print $nixos_config_path
-  exit 0
-fi
-
 print_info "Deploying target system configuration"
-if [[ "$is_target_host" ]]
+if [[ "$is_target_host" || "$operation" = "build" ]]
 then
   # local deploy
 
+  print_info "Building target system configuration"
+  nix build "path:$MACHINES_PATH#nixosConfigurations.$hostname.config.system.build.toplevel" --out-link "$local_temp_dir/nixos-config-$hostname"
+  readonly nixos_config_path=$(realpath "$local_temp_dir/nixos-config-$hostname")
+
+  if [[ "$operation" = "build" ]]
+  then
+    print_info "Build completed"
+    print $nixos_config_path
+    exit 0
+  fi
+
   if [[ -n "$set_profile" ]]
   then
     sudo nix-env --profile /nix/var/nix/profiles/system --set $nixos_config_path
@@ -140,8 +139,7 @@ then
 else
   # remote deploy
 
-  nix copy --file "$MACHINES_PATH" "nixosSystemDerivations.$hostname" --to "ssh://root@$via_hostname"
-  #nix copy --substitute-on-destination --file "$MACHINES_PATH" "nixosSystemDerivations.$hostname" --to "ssh://root@$via_hostname"
+  nix copy --substitute-on-destination --to "ssh://root@$via_hostname" "path:$MACHINES_PATH#nixosConfigurations.$hostname.config.system.build.toplevel"
 
   # The manual way to do it (this is in theory also supported by nixos-rebuild by using '-I')
 
diff --git a/channels/nixos-19.09/default.nix b/channels/nixos-19.09/default.nix
index 000e694..9637fd5 100644
--- a/channels/nixos-19.09/default.nix
+++ b/channels/nixos-19.09/default.nix
@@ -7,6 +7,5 @@ let
   channelDef = fromJSON ( readFile ./channel.json );
 
 in fetchGit {
-  inherit name;
   inherit (channelDef) url rev ref;
 }
diff --git a/channels/nixos-unstable/default.nix b/channels/nixos-unstable/default.nix
index 000e694..9637fd5 100644
--- a/channels/nixos-unstable/default.nix
+++ b/channels/nixos-unstable/default.nix
@@ -7,6 +7,5 @@ let
   channelDef = fromJSON ( readFile ./channel.json );
 
 in fetchGit {
-  inherit name;
   inherit (channelDef) url rev ref;
 }
diff --git a/configuration.nix b/configuration.nix
index 7537d37..01cbd10 100644
--- a/configuration.nix
+++ b/configuration.nix
@@ -22,12 +22,31 @@ let
           else builtins.throw "Cannot find layer `${layerName}`";
 
   layerImports = map layerPath dotfilesConfig.layers;
+
+  normalSystemConfiguration = (lib.attrsets.optionalAttrs (!isIso) {
+    imports = [ (path + "/hardware-configuration.nix") ];
+    # Bootloader
+    boot.loader.systemd-boot.enable = (installResult.bootloader == "efi");
+    boot.loader.efi.canTouchEfiVariables = (installResult.bootloader == "efi");
+    boot.loader.grub.enable = (installResult.bootloader == "bios");
+    boot.loader.grub.device = installResult.installedBlockDevice;
+
+    boot.initrd.luks.devices = if installResult.luks then {
+      cryptvol = {
+        device = "/dev/disk/by-uuid/" + installResult.luksPartitionUuid;
+        allowDiscards = true;
+      };
+    } else {};
+  });
 in
-({
+{
   imports = [
     ./modules
     (path + "/configuration.nix")
-  ] ++ layerImports ++ (lib.lists.optional (!isIso) (path + "/hardware-configuration.nix"));
+    normalSystemConfiguration
+  ] ++ layerImports;
+
+  _module.args.isIso = lib.mkDefault false;
 
   nixpkgs.config = {
     packageOverrides = import ./pkgs;
@@ -35,8 +54,9 @@ in
 
   # Pin channel in nix path
   nix.nixPath = [ "nixpkgs=${channel}" ];
+  nix.registry.nixpkgs.flake = channel;
   # Make nixpkgs path available inside of the configuration
-  _module.args.nixpkgsPath = channel;
+  #_module.args.nixpkgsPath = channel;
 
   environment.shellAliases = {
     # nixos-option won't run without a configuration. With an empty config it does not show configured values, but can at least be used to search options and show default values.
@@ -45,18 +65,4 @@ in
 
   # Default hostname ist machine directory name
   networking.hostName = lib.mkDefault name;
-
-} // (lib.attrsets.optionalAttrs (!isIso) {
-  # Bootloader
-  boot.loader.systemd-boot.enable = (installResult.bootloader == "efi");
-  boot.loader.efi.canTouchEfiVariables = (installResult.bootloader == "efi");
-  boot.loader.grub.enable = (installResult.bootloader == "bios");
-  boot.loader.grub.device = installResult.installedBlockDevice;
-
-  boot.initrd.luks.devices = if installResult.luks then {
-    cryptvol = {
-      device = "/dev/disk/by-uuid/" + installResult.luksPartitionUuid;
-      allowDiscards = true;
-    };
-  } else {};
-}))
+}
diff --git a/flake.lock b/flake.lock
index 93caa22..7c9851b 100644
--- a/flake.lock
+++ b/flake.lock
@@ -2,11 +2,11 @@
   "nodes": {
     "nixpkgs": {
       "locked": {
-        "lastModified": 1605988311,
-        "narHash": "sha256-PA+kgq46NApOAJlmBNJHs5DwsIrY+jodM0e4g7VtXyY=",
+        "lastModified": 1607690238,
+        "narHash": "sha256-9QFXxj6pjmHr+950E3/gXo9cz50l0AbFCHZR5eixkXw=",
         "owner": "nixos",
         "repo": "nixpkgs",
-        "rev": "2247d824fe07f16325596acc7faa286502faffd1",
+        "rev": "8006772a054ce57ca18c5955dcd6ec9a62577473",
         "type": "github"
       },
       "original": {
diff --git a/layers/workstation.nix b/layers/workstation.nix
index 3a3654a..377ec82 100644
--- a/layers/workstation.nix
+++ b/layers/workstation.nix
@@ -6,6 +6,7 @@
     ./vscode.nix
   ];
 
+  nix.package = pkgs.nixUnstable;
   nix.extraOptions = ''
     experimental-features = nix-command flakes
   '';
diff --git a/layers/zsh.nix b/layers/zsh.nix
index 4cb9a09..cb9ddec 100644
--- a/layers/zsh.nix
+++ b/layers/zsh.nix
@@ -1,4 +1,4 @@
-{ pkgs, ... }:
+{ pkgs, config, ... }:
 
 let
   promptPath = ../zsh/prompt;
@@ -112,6 +112,8 @@ in
       alias icat="kitty +kitten icat"
     fi
 
+    source ${config.nix.package.src}/misc/zsh/completion.zsh
+
     if (( $+commands[direnv] ))
     then
       eval "$(direnv hook zsh)"
diff --git a/machine-manager.nix b/machine-manager.nix
index a92a702..db81003 100644
--- a/machine-manager.nix
+++ b/machine-manager.nix
@@ -1,85 +1,109 @@
 # entry point for machine configurations:
 # (import <repo-path> { machinesDir=./machines }).<netname>.configurations.<hostname>
 
-{ machinesDir, extraLayersDir }:
+{ flakeInputs, flakeOutputs, machinesDir, extraLayersDir }:
 
 with builtins;
 let
   # defaultChannel :: path (channel)
-  defaultChannel = loadChannel "nixos-unstable";
+  #defaultChannel = loadChannel "nixos-unstable";
 
   # helpers :: { *: ? }
   helpers = import ./helpers.nix;
 
   # channelsDir :: path
-  channelsDir = ./channels;
+  #channelsDir = ./channels;
   # loadChannel :: string -> path (channel)
-  loadChannel = name: import (channelsDir + "/${name}") name;
+  #loadChannel = name: import (channelsDir + "/${name}") name;
   # allChannels :: { *: path (channel) }
-  allChannels = with helpers; keysToAttrs loadChannel (readFilterDir (filterAnd [(not filterDirHidden) filterDirDirs]) channelsDir);
+  #allChannels = with helpers; keysToAttrs loadChannel (readFilterDir (filterAnd [(not filterDirHidden) filterDirDirs]) channelsDir);
   # getMachineChannel :: string -> path
-  getMachineChannel = { name, path }:
-    let
-      channelFile = path + "/channel.nix";
-    in
-      if (pathExists channelFile)
-        then (import channelFile) allChannels
-        else defaultChannel;
+  getMachineChannel = _: flakeInputs.nixpkgs-unstable;
+  #getMachineChannel = { name, path }:
+  #  let
+  #    channelFile = path + "/channel.nix";
+  #  in
+  #    if (pathExists channelFile)
+  #      then (import channelFile) allChannels
+  #      else defaultChannel;
   # machineChannels :: { *: path }
   machineChannels = withMachines getMachineChannel;
 
   machinesDirContents = readDir machinesDir;
   machineNames = filter (p: machinesDirContents.${p} == "directory") (attrNames machinesDirContents);
   withMachines = lambda: listToAttrs (map (m: {name = m; value = lambda { name = m; path = (machinesDir + "/${m}"); }; }) machineNames);
-  mkMachineConfig = { name, path, isIso ? false }: (
+  mkMachineConfig = { name, path, isIso }: (
     import ./configuration.nix {
       inherit name path isIso extraLayersDir;
       channel = machineChannels.${name};
     }
   );
+  evaluateConfig = pkgs: args: (import "${pkgs}/nixos/lib/eval-config.nix" args).config;
   mkNixosSystemDerivation = { name, path }:
     let
-      channel = machineChannels.${name};
-      configuration = mkMachineConfig { inherit name path; };
-      # Importing <nixpkgs/nixos> results in a nixos system closure
-      nixos = import "${channel}/nixos" {
-        system = "x86_64-linux";
-        inherit configuration;
-      };
-    in
-      nixos.system;
-  mkNixosIsoDerivation = { name, path }:
-    let
-      channel = machineChannels.${name};
-      configuration = { config, ... }:
-      {
-        imports = [
-          (mkMachineConfig { inherit name path; isIso = true; })
-          <nixpkgs/nixos/modules/installer/cd-dvd/iso-image.nix>
-          <nixpkgs/nixos/modules/profiles/all-hardware.nix>
-          <nixpkgs/nixos/modules/profiles/base.nix>
+      channel = flakeInputs.nixpkgs-unstable;
+      configuration = mkMachineConfig { inherit name path; isIso = false; };
+      isoConfiguration = mkMachineConfig { inherit name path; isIso = true; };
+      system = "x86_64-linux";
+      iso = (evaluateConfig channel {
+        inherit system;
+        modules = [
+          isoConfiguration
+          (mkAdditionalIsoConfig name)
         ];
-        isoImage.isoName = "${config.isoImage.isoBaseName}-${config.system.nixos.label}-isohost-${name}.iso";
-        isoImage.volumeID = substring 0 11 "NIXOS_ISO";
-
-        isoImage.makeEfiBootable = true;
-        isoImage.makeUsbBootable = true;
-        boot.loader.grub.memtest86.enable = true;
-
-      };
-      # Importing <nixpkgs/nixos> results in a nixos system closure
-      nixos = import "${channel}/nixos" {
-        system = "x86_64-linux";
-        inherit configuration;
-      };
+      }).system.build.isoImage;
+      sdImage = (evaluateConfig channel {
+        inherit system;
+        modules = [
+          isoConfiguration
+          (mkAdditionalSdCardConfig name)
+        ];
+      }).system.build.sdImage;
     in
-      nixos.config.system.build.isoImage;
+    channel.lib.nixosSystem {
+      inherit system;
+      modules = [
+        configuration
+        {
+          system.build = {
+            inherit iso sdImage;
+          };
+        }
+      ];
+    };
+  mkAdditionalIsoConfig = name: { config, modulesPath, ... }: {
+    imports = [
+      "${modulesPath}/installer/cd-dvd/iso-image.nix"
+      "${modulesPath}/profiles/all-hardware.nix"
+      "${modulesPath}/profiles/base.nix"
+    ];
+    isoImage.isoName = "${config.isoImage.isoBaseName}-${config.system.nixos.label}-isohost-${name}.iso";
+    isoImage.volumeID = substring 0 11 "NIXOS_ISO";
+    isoImage.makeEfiBootable = true;
+    isoImage.makeUsbBootable = true;
+    boot.loader.grub.memtest86.enable = true;
+    _module.args.isIso = true;
+  };
+  mkAdditionalSdCardConfig = name: { config, modulesPath, ... }: {
+    imports = [
+      "${modulesPath}/installer/cd-dvd/sd-image.nix"
+      "${modulesPath}/profiles/all-hardware.nix"
+      "${modulesPath}/profiles/base.nix"
+    ];
+    sdImage.populateRootCommands = "";
+    sdImage.populateFirmwareCommands = "";
+    boot.loader.grub.enable = false;
+    boot.loader.generic-extlinux-compatible.enable = true;
+    _module.args.isIso = true;
+  };
 
 in
 {
-  configurations = withMachines mkMachineConfig;
+  # TODO remove
+  # configurations = withMachines mkMachineConfig;
+  # nixosIsoDerivations = withMachines mkNixosIsoDerivation;
+  # channels = machineChannels;
+
   nixosSystemDerivations = withMachines mkNixosSystemDerivation;
-  nixosIsoDerivations = withMachines mkNixosIsoDerivation;
   machineTemplates = withMachines ({name, path}: import (path + /template.nix));
-  channels = machineChannels;
 }
-- 
GitLab