integrate VM definitions

This commit is contained in:
Pim Kunis 2024-01-28 11:48:13 +01:00
parent e57f80df82
commit 472175c5a3
6 changed files with 296 additions and 216 deletions

View file

@ -39,6 +39,7 @@
lib = pkgs.lib; lib = pkgs.lib;
pkgs-unstable = nixpkgs-unstable.legacyPackages.${system}; pkgs-unstable = nixpkgs-unstable.legacyPackages.${system};
machines = import ./nixos/machines; machines = import ./nixos/machines;
physicalMachines = lib.filterAttrs (n: v: v.type == "physical") machines;
# TODO: Maybe use mergeAttrLists # TODO: Maybe use mergeAttrLists
mkNixosSystems = systemDef: mkNixosSystems = systemDef:
nixpkgs.lib.foldlAttrs nixpkgs.lib.foldlAttrs
@ -47,12 +48,12 @@
"${name}" = nixpkgs.lib.nixosSystem (systemDef machine); "${name}" = nixpkgs.lib.nixosSystem (systemDef machine);
}) })
{ } { }
machines; physicalMachines;
mkDeployNodes = nodeDef: mkDeployNodes = nodeDef:
nixpkgs.lib.foldlAttrs nixpkgs.lib.foldlAttrs
(acc: name: machine: acc // { "${name}" = nodeDef machine; }) (acc: name: machine: acc // { "${name}" = nodeDef machine; })
{ } { }
machines; physicalMachines;
in in
{ {
devShells.${system}.default = pkgs.mkShell { devShells.${system}.default = pkgs.mkShell {
@ -76,15 +77,8 @@
nixosConfigurations = mkNixosSystems (machine: { nixosConfigurations = mkNixosSystems (machine: {
inherit system; inherit system;
specialArgs = { inherit kubenix dns; }; specialArgs = { inherit machines machine kubenix dns microvm disko agenix; };
modules = [ modules = [ ./nixos ];
microvm.nixosModules.host
machine.nixosModule
disko.nixosModules.disko
agenix.nixosModules.default
./nixos
{ networking.hostName = machine.name; }
];
}); });
deploy = { deploy = {
@ -92,10 +86,11 @@
user = "root"; user = "root";
nodes = mkDeployNodes (machine: { nodes = mkDeployNodes (machine: {
hostname = machine.hostName; # TODO: simply get this from nixos configuration?
hostname = "${machine.hostName}.${machine.domain}";
profiles.system = { profiles.system = {
path = deploy-rs.lib.${system}.activate.nixos path = deploy-rs.lib.${system}.activate.nixos
self.nixosConfigurations.${machine.name}; self.nixosConfigurations.${machine.hostName};
}; };
}); });
}; };
@ -103,56 +98,5 @@
checks = builtins.mapAttrs checks = builtins.mapAttrs
(system: deployLib: deployLib.deployChecks self.deploy) (system: deployLib: deployLib.deployChecks self.deploy)
deploy-rs.lib; deploy-rs.lib;
apps.${system} =
let
hostNames = builtins.concatStringsSep " " (builtins.map (host: "\"${host.config.networking.fqdn}\"") (builtins.attrValues self.nixosConfigurations));
in
{
reboot-all-vms =
let
reboot-all-vms = pkgs.writeScriptBin "reboot-all-vms" ''
hostNames=(${hostNames})
for hostName in ''${hostNames[@]}; do
units=$(${pkgs.openssh}/bin/ssh root@$hostName systemctl list-units --all)
microvmUnits=$(${pkgs.coreutils}/bin/echo "$units" | ${pkgs.gnugrep}/bin/grep 'microvm@.*\.service' | ${pkgs.gawkInteractive}/bin/awk '{print $1}')
if [ -n "$microvmUnits" ]; then
for microvmUnit in "$microvmUnits"; do
${pkgs.coreutils}/bin/echo "Restarting $microvmUnit on $hostName"
${pkgs.openssh}/bin/ssh root@$hostName systemctl restart "$microvmUnit"
done
fi
done
'';
in
{
type = "app";
program = "${reboot-all-vms}/bin/reboot-all-vms";
};
reboot-vm =
let
reboot-vm = pkgs.writeScriptBin "reboot-vm" ''
if [ -z "$1" ]; then
${pkgs.coreutils}/bin/echo "Please provide a VM name!"
exit 1
fi
hostNames=(${hostNames})
unitName="microvm@$1.service"
for hostName in ''${hostNames[@]}; do
units=$(${pkgs.openssh}/bin/ssh root@$hostName systemctl list-units --all)
if [[ "''${units[@]}" =~ "$unitName" ]]; then
${pkgs.coreutils}/bin/echo "Restarting $unitName on $hostName"
${pkgs.openssh}/bin/ssh root@$hostName systemctl restart "$unitName"
fi
done
'';
in
{
type = "app";
program = "${reboot-vm}/bin/reboot-vm";
};
};
}; };
} }

View file

@ -1,142 +1,168 @@
{ pkgs, config, lib, modulesPath, ... }: { { pkgs, config, lib, modulesPath, machine, microvm, disko, agenix, machines, ... }: {
imports = [ imports = [
(modulesPath + "/installer/scan/not-detected.nix") (modulesPath + "/installer/scan/not-detected.nix")
./modules ./modules
./lab.nix ./lab.nix
machine.nixosModule
disko.nixosModules.disko
agenix.nixosModules.default
microvm.nixosModules.host
]; ];
boot = { config = {
kernelModules = [ "kvm-intel" ]; boot = {
extraModulePackages = [ ]; kernelModules = [ "kvm-intel" ];
extraModulePackages = [ ];
initrd = { initrd = {
availableKernelModules = [ availableKernelModules = [
"ahci" "ahci"
"xhci_pci" "xhci_pci"
"nvme" "nvme"
"usbhid" "usbhid"
"usb_storage" "usb_storage"
"sd_mod" "sd_mod"
"sdhci_pci" "sdhci_pci"
]; ];
kernelModules = [ ]; kernelModules = [ ];
}; };
loader = { loader = {
systemd-boot.enable = true; systemd-boot.enable = true;
efi.canTouchEfiVariables = true; efi.canTouchEfiVariables = true;
};
};
time.timeZone = "Europe/Amsterdam";
i18n = {
defaultLocale = "en_US.UTF-8";
extraLocaleSettings = {
LC_ADDRESS = "nl_NL.UTF-8";
LC_IDENTIFICATION = "nl_NL.UTF-8";
LC_MEASUREMENT = "nl_NL.UTF-8";
LC_MONETARY = "nl_NL.UTF-8";
LC_NAME = "nl_NL.UTF-8";
LC_NUMERIC = "nl_NL.UTF-8";
LC_PAPER = "nl_NL.UTF-8";
LC_TELEPHONE = "nl_NL.UTF-8";
LC_TIME = "nl_NL.UTF-8";
};
};
services = {
openssh = {
enable = true;
openFirewall = true;
settings = {
PasswordAuthentication = false;
KbdInteractiveAuthentication = false;
}; };
}; };
xserver = { time.timeZone = "Europe/Amsterdam";
layout = "us";
xkbVariant = ""; i18n = {
defaultLocale = "en_US.UTF-8";
extraLocaleSettings = {
LC_ADDRESS = "nl_NL.UTF-8";
LC_IDENTIFICATION = "nl_NL.UTF-8";
LC_MEASUREMENT = "nl_NL.UTF-8";
LC_MONETARY = "nl_NL.UTF-8";
LC_NAME = "nl_NL.UTF-8";
LC_NUMERIC = "nl_NL.UTF-8";
LC_PAPER = "nl_NL.UTF-8";
LC_TELEPHONE = "nl_NL.UTF-8";
LC_TIME = "nl_NL.UTF-8";
};
}; };
};
users.users.root.openssh.authorizedKeys.keys = [ services = {
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOodpLr+FDRyKyHjucHizNLVFHZ5AQmE9GmxMnOsSoaw pimkunis@thinkpadpim" openssh = {
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINUZp4BCxf7uLa1QWonx/Crf8tYZ5MKIZ+EuaBa82LrV user@user-laptop" enable = true;
]; openFirewall = true;
programs = { settings = {
ssh = { PasswordAuthentication = false;
knownHosts = { KbdInteractiveAuthentication = false;
dmz = {
hostNames = [ "*.dmz" ];
publicKey =
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAX2IhgHNxC6JTvLu9cej+iWuG+uJFMXn4AiRro9533x";
certAuthority = true;
};
hypervisors = {
hostNames = [ "*.hyp" ];
publicKey =
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFzRkH3d/KVJQouswY/DMpenWbDFVOnI3Vut0xR0e1tb";
certAuthority = true;
}; };
}; };
xserver = {
layout = "us";
xkbVariant = "";
};
}; };
neovim = { users.users.root.openssh.authorizedKeys.keys = [
enable = true; "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOodpLr+FDRyKyHjucHizNLVFHZ5AQmE9GmxMnOsSoaw pimkunis@thinkpadpim"
vimAlias = true; "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINUZp4BCxf7uLa1QWonx/Crf8tYZ5MKIZ+EuaBa82LrV user@user-laptop"
viAlias = true; ];
programs = {
ssh = {
knownHosts = {
dmz = {
hostNames = [ "*.dmz" ];
publicKey =
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAX2IhgHNxC6JTvLu9cej+iWuG+uJFMXn4AiRro9533x";
certAuthority = true;
};
hypervisors = {
hostNames = [ "*.hyp" ];
publicKey =
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFzRkH3d/KVJQouswY/DMpenWbDFVOnI3Vut0xR0e1tb";
certAuthority = true;
};
};
};
neovim = {
enable = true;
vimAlias = true;
viAlias = true;
};
}; };
};
nixpkgs = { nixpkgs = {
config.allowUnfree = true; config.allowUnfree = true;
hostPlatform = "x86_64-linux"; hostPlatform = "x86_64-linux";
}; };
environment.systemPackages = with pkgs; [ environment.systemPackages = with pkgs; [
neofetch neofetch
wget wget
git git
btop btop
htop htop
ripgrep ripgrep
dig dig
tree tree
file file
tcpdump tcpdump
lsof lsof
parted parted
radvd radvd
]; ];
hardware.cpu.intel.updateMicrocode = hardware.cpu.intel.updateMicrocode = config.hardware.enableRedistributableFirmware;
lib.mkDefault config.hardware.enableRedistributableFirmware;
age.identityPaths = [ "/etc/age_ed25519" ]; age.identityPaths = [ "/etc/age_ed25519" ];
virtualisation.libvirtd.enable = true; virtualisation.libvirtd.enable = true;
nix = { nix = {
package = pkgs.nixFlakes; package = pkgs.nixFlakes;
extraOptions = '' extraOptions = ''
experimental-features = nix-command flakes experimental-features = nix-command flakes
''; '';
}; };
system = { system = {
stateVersion = "23.05"; stateVersion = "23.05";
activationScripts.diff = '' activationScripts.diff = ''
if [[ -e /run/current-system ]]; then if [[ -e /run/current-system ]]; then
${pkgs.nix}/bin/nix store diff-closures /run/current-system "$systemConfig" ${pkgs.nix}/bin/nix store diff-closures /run/current-system "$systemConfig"
fi fi
''; '';
};
microvm.vms =
let
vmsForHypervisor = lib.attrValues (lib.filterAttrs (n: v: v.type == "virtual" && v.hypervisorName == machine.hostName) machines);
in
lib.attrsets.mergeAttrsList (map
(vm:
{
"${vm.hostName}" = {
# TODO Simplify?
specialArgs = { inherit agenix disko pkgs lib microvm; machine = vm; hypervisorConfig = config; };
config = {
imports = [
./vm.nix
];
};
};
}
)
vmsForHypervisor
);
}; };
} }

View file

@ -1,7 +1,9 @@
{ {
jefke = { jefke = {
name = "jefke"; # TODO: directly set and read this from nixos config.
hostName = "jefke.hyp"; hostName = "jefke";
domain = "hyp";
type = "physical";
nixosModule.lab = { nixosModule.lab = {
terraformDatabase.enable = true; terraformDatabase.enable = true;
@ -20,8 +22,9 @@
}; };
atlas = { atlas = {
name = "atlas"; hostName = "atlas";
hostName = "atlas.hyp"; domain = "hyp";
type = "physical";
nixosModule = { config, ... }: nixosModule = { config, ... }:
let inherit (config.lab.networking) dmzServicesIPv4 dmzServicesIPv6; in let inherit (config.lab.networking) dmzServicesIPv4 dmzServicesIPv6; in
@ -49,8 +52,9 @@
}; };
lewis = { lewis = {
name = "lewis"; hostName = "lewis";
hostName = "lewis.hyp"; domain = "hyp";
type = "physical";
nixosModule = { pkgs, ... }: { nixosModule = { pkgs, ... }: {
lab = { lab = {
@ -67,35 +71,21 @@
userCert = builtins.readFile ./lewis_user_ed25519-cert.pub; userCert = builtins.readFile ./lewis_user_ed25519-cert.pub;
}; };
}; };
};
};
microvm.vms.my-microvm.config = { my-microvm = {
services.openssh.enable = true; hostName = "my-microvm";
networking.firewall.enable = false; domain = "dmz";
type = "virtual";
hypervisorName = "lewis";
users.users.root.openssh.authorizedKeys.keys = [ nixosModule = { pkgs, config, ... }: {
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOodpLr+FDRyKyHjucHizNLVFHZ5AQmE9GmxMnOsSoaw pimkunis@thinkpadpim" programs.bash.interactiveShellInit = ''
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINUZp4BCxf7uLa1QWonx/Crf8tYZ5MKIZ+EuaBa82LrV user@user-laptop" echo "Hello world from inside a virtual machine!" | ${pkgs.lolcat}/bin/lolcat
]; '';
programs.bash.interactiveShellInit = '' lab.vmMacAddress = "BA:DB:EE:F0:00:00";
echo "Hello world from inside a virtual machine!" | ${pkgs.lolcat}/bin/lolcat
'';
microvm = {
shares = [{
source = "/nix/store";
mountPoint = "/nix/.ro-store";
tag = "ro-store";
proto = "virtiofs";
}];
interfaces = [{
type = "tap";
id = "vm-my-microvm";
mac = "48:2D:63:E1:C5:39";
}];
};
};
}; };
}; };
} }

View file

@ -1,4 +1,4 @@
{ lib, config, ... }: { lib, config, machine, ... }:
let cfg = config.lab.networking; let cfg = config.lab.networking;
in { in {
imports = [ ./dmz ]; imports = [ ./dmz ];
@ -89,17 +89,18 @@ in {
config = { config = {
networking = { networking = {
domain = "hyp"; hostName = machine.hostName;
domain = machine.domain;
nftables.enable = true;
useDHCP = machine.type == "virtual";
firewall = { firewall = {
enable = true; enable = true;
checkReversePath = false; checkReversePath = false;
}; };
nftables.enable = true;
useDHCP = false;
}; };
systemd.network = { systemd.network = lib.mkIf (machine.type == "physical") {
enable = true; enable = true;
netdevs = { netdevs = {

View file

@ -1,4 +1,4 @@
{ lib, config, ... }: { lib, config, machine, ... }:
let cfg = config.lab.storage; let cfg = config.lab.storage;
in { in {
options.lab.storage = { options.lab.storage = {
@ -25,7 +25,7 @@ in {
}; };
}; };
config = { config = lib.mkIf (machine.type == "physical") {
fileSystems.${cfg.dataMountPoint}.device = cfg.dataPartition; fileSystems.${cfg.dataMountPoint}.device = cfg.dataPartition;
# TODO: Rename this to 'osDisk'. Unfortunately, we would need to run nixos-anywhere again then. # TODO: Rename this to 'osDisk'. Unfortunately, we would need to run nixos-anywhere again then.

119
nixos/vm.nix Normal file
View file

@ -0,0 +1,119 @@
{ pkgs, lib, config, agenix, disko, machine, hypervisorConfig, ... }: {
imports = [
./modules
./lab.nix
machine.nixosModule
disko.nixosModules.disko
agenix.nixosModules.default
];
options.lab.vmMacAddress = lib.mkOption {
type = lib.types.str;
description = ''
The MAC address of the VM's main NIC.
'';
};
# TODO: remove overlap with physical nixos module
# Perhaps a sane defaults module?
config = {
system.stateVersion = hypervisorConfig.system.stateVersion;
time.timeZone = "Europe/Amsterdam";
i18n = {
defaultLocale = "en_US.UTF-8";
extraLocaleSettings = {
LC_ADDRESS = "nl_NL.UTF-8";
LC_IDENTIFICATION = "nl_NL.UTF-8";
LC_MEASUREMENT = "nl_NL.UTF-8";
LC_MONETARY = "nl_NL.UTF-8";
LC_NAME = "nl_NL.UTF-8";
LC_NUMERIC = "nl_NL.UTF-8";
LC_PAPER = "nl_NL.UTF-8";
LC_TELEPHONE = "nl_NL.UTF-8";
LC_TIME = "nl_NL.UTF-8";
};
};
services = {
openssh = {
enable = true;
openFirewall = true;
settings = {
PasswordAuthentication = false;
KbdInteractiveAuthentication = false;
};
};
xserver = {
layout = "us";
xkbVariant = "";
};
};
users.users.root.openssh.authorizedKeys.keys = [
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOodpLr+FDRyKyHjucHizNLVFHZ5AQmE9GmxMnOsSoaw pimkunis@thinkpadpim"
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINUZp4BCxf7uLa1QWonx/Crf8tYZ5MKIZ+EuaBa82LrV user@user-laptop"
];
programs = {
ssh = {
knownHosts = {
dmz = {
hostNames = [ "*.dmz" ];
publicKey =
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAX2IhgHNxC6JTvLu9cej+iWuG+uJFMXn4AiRro9533x";
certAuthority = true;
};
hypervisors = {
hostNames = [ "*.hyp" ];
publicKey =
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFzRkH3d/KVJQouswY/DMpenWbDFVOnI3Vut0xR0e1tb";
certAuthority = true;
};
};
};
neovim = {
enable = true;
vimAlias = true;
viAlias = true;
};
};
environment.systemPackages = with pkgs; [
neofetch
wget
git
btop
htop
ripgrep
dig
tree
file
tcpdump
lsof
parted
radvd
];
microvm = {
shares = [{
source = "/nix/store";
mountPoint = "/nix/.ro-store";
tag = "ro-store";
proto = "virtiofs";
}];
interfaces = [{
type = "tap";
id = "vm-${machine.hostName}";
mac = config.lab.vmMacAddress;
}];
};
};
}