raspberrypi #70

Merged
pim merged 5 commits from raspberrypi into master 2024-02-28 20:42:51 +00:00
7 changed files with 248 additions and 166 deletions

View file

@ -198,6 +198,22 @@
"type": "github" "type": "github"
} }
}, },
"nixos-hardware": {
"locked": {
"lastModified": 1708594753,
"narHash": "sha256-c/gH7iXS/IYH9NrFOT+aJqTq+iEBkvAkpWuUHGU3+f0=",
"owner": "NixOS",
"repo": "nixos-hardware",
"rev": "3f7d0bca003eac1a1a7f4659bbab9c8f8c2a0958",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "master",
"repo": "nixos-hardware",
"type": "github"
}
},
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1702272962, "lastModified": 1702272962,
@ -253,6 +269,7 @@
"disko": "disko", "disko": "disko",
"dns": "dns", "dns": "dns",
"microvm": "microvm", "microvm": "microvm",
"nixos-hardware": "nixos-hardware",
"nixpkgs": "nixpkgs_2", "nixpkgs": "nixpkgs_2",
"nixpkgs-unstable": "nixpkgs-unstable" "nixpkgs-unstable": "nixpkgs-unstable"
} }

View file

@ -5,6 +5,7 @@
nixpkgs.url = "github:nixos/nixpkgs/nixos-23.11"; nixpkgs.url = "github:nixos/nixpkgs/nixos-23.11";
nixpkgs-unstable.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; nixpkgs-unstable.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
deploy-rs.url = "github:serokell/deploy-rs"; deploy-rs.url = "github:serokell/deploy-rs";
nixos-hardware.url = "github:NixOS/nixos-hardware/master";
disko = { disko = {
url = "github:nix-community/disko"; url = "github:nix-community/disko";
@ -28,12 +29,12 @@
}; };
outputs = outputs =
{ self, nixpkgs, deploy-rs, disko, agenix, nixpkgs-unstable, dns, microvm, ... }: { self, nixpkgs, deploy-rs, disko, agenix, nixpkgs-unstable, dns, microvm, nixos-hardware, ... }:
let let
system = "x86_64-linux"; controllerArch = "x86_64-linux";
pkgs = nixpkgs.legacyPackages.${system}; pkgs = nixpkgs.legacyPackages.${controllerArch};
lib = pkgs.lib; lib = pkgs.lib;
pkgs-unstable = nixpkgs-unstable.legacyPackages.${system}; pkgs-unstable = nixpkgs-unstable.legacyPackages.${controllerArch};
machines = import ./nixos/machines; machines = import ./nixos/machines;
physicalMachines = lib.filterAttrs (n: v: v.type == "physical") machines; physicalMachines = lib.filterAttrs (n: v: v.type == "physical") machines;
mkNixosSystems = systemDef: mkNixosSystems = systemDef:
@ -48,7 +49,7 @@
physicalMachines; physicalMachines;
in in
{ {
devShells.${system}.default = pkgs.mkShell { devShells.${controllerArch}.default = pkgs.mkShell {
packages = with pkgs; [ packages = with pkgs; [
libsecret libsecret
# TODO: using nixos-anywhere from nixos-unstable produces buffer overflow. # TODO: using nixos-anywhere from nixos-unstable produces buffer overflow.
@ -65,11 +66,12 @@
]; ];
}; };
formatter.${system} = pkgs.nixfmt; formatter.${controllerArch} = pkgs.nixfmt;
nixosConfigurations = mkNixosSystems (name: machine: { nixosConfigurations = mkNixosSystems (name: machine: {
inherit system; system = machine.arch;
specialArgs = { inherit machines machine dns microvm disko agenix; };
specialArgs = { inherit machines machine dns microvm disko agenix nixos-hardware; };
modules = [ modules = [
./nixos ./nixos
{ networking.hostName = name; } { networking.hostName = name; }
@ -83,14 +85,25 @@
nodes = mkDeployNodes (name: machine: { nodes = mkDeployNodes (name: machine: {
hostname = self.nixosConfigurations.${name}.config.networking.fqdn; hostname = self.nixosConfigurations.${name}.config.networking.fqdn;
profiles.system = { profiles.system = {
path = deploy-rs.lib.${system}.activate.nixos remoteBuild = machine.arch != controllerArch;
path = deploy-rs.lib."${machine.arch}".activate.nixos
self.nixosConfigurations.${name}; self.nixosConfigurations.${name};
}; };
}); });
}; };
# Deploy-rs' flake checks seem broken for architectures different from the deployment machine.
# We skip these here.
checks = builtins.mapAttrs checks = builtins.mapAttrs
(system: deployLib: deployLib.deployChecks self.deploy) (system: deployLib:
deployLib.deployChecks (self.deploy // {
nodes = (lib.attrsets.filterAttrs
(name: node:
machines.${name}.arch == controllerArch
)
self.deploy.nodes);
})
)
deploy-rs.lib; deploy-rs.lib;
}; };
} }

View file

@ -1,6 +1,26 @@
# TODO: Create a nixos module system for this. (mkMerge)
# That way, we don't have to specify isRaspberryPi on every machine... etc.
{ {
warwick = {
type = "physical";
arch = "aarch64-linux";
isRaspberryPi = true;
isHypervisor = false;
isVirtualMachine = false;
nixosModule.lab = {
storage = {
osDisk = "/dev/sda";
};
};
};
atlas = { atlas = {
type = "physical"; type = "physical";
arch = "x86_64-linux";
isRaspberryPi = false;
isHypervisor = true;
isVirtualMachine = false;
nixosModule.lab = { nixosModule.lab = {
storage = { storage = {
@ -18,25 +38,31 @@
jefke = { jefke = {
type = "physical"; type = "physical";
arch = "x86_64-linux";
isRaspberryPi = false;
isHypervisor = true;
isVirtualMachine = false;
nixosModule = { nixosModule.lab = {
lab = { storage = {
storage = { osDisk = "/dev/sda";
osDisk = "/dev/sda"; dataPartition = "/dev/nvme0n1p1";
dataPartition = "/dev/nvme0n1p1"; };
};
ssh = { ssh = {
useCertificates = true; useCertificates = true;
hostCert = builtins.readFile ./certificates/jefke/host_ed25519.crt; hostCert = builtins.readFile ./certificates/jefke/host_ed25519.crt;
userCert = builtins.readFile ./certificates/jefke/user_ed25519.crt; userCert = builtins.readFile ./certificates/jefke/user_ed25519.crt;
};
}; };
}; };
}; };
lewis = { lewis = {
type = "physical"; type = "physical";
arch = "x86_64-linux";
isRaspberryPi = false;
isHypervisor = true;
isVirtualMachine = false;
nixosModule.lab = { nixosModule.lab = {
backups.enable = true; backups.enable = true;
@ -59,18 +85,23 @@
hermes = { hermes = {
type = "virtual"; type = "virtual";
hypervisorName = "lewis"; hypervisorName = "lewis";
isRaspberryPi = false;
isVirtualMachine = true;
isHypervisor = false;
nixosModule = { config, ... }: { nixosModule = { config, ... }: {
lab = { lab = {
networking.dmz.services.enable = true; networking = {
dmz.services.enable = true;
staticNetworking = true;
staticIPv4 = config.lab.networking.dmz.ipv4.services;
staticIPv6 = config.lab.networking.dmz.ipv6.services;
};
vm = { vm = {
# TODO: would be cool to create a check that a mac address is only ever assigned to one VM. # TODO: would be cool to create a check that a mac address is only ever assigned to one VM.
# TODO: idea: what if we generated these IDs by hashing the host name and reducing that to the amount of hosts possible? # TODO: idea: what if we generated these IDs by hashing the host name and reducing that to the amount of hosts possible?
id = 7; id = 7;
staticNetworking = true;
staticIPv4 = config.lab.networking.dmz.ipv4.services;
staticIPv6 = config.lab.networking.dmz.ipv6.services;
shares = [{ shares = [{
name = "dnsmasq"; name = "dnsmasq";
@ -84,6 +115,9 @@
maestro = { maestro = {
type = "virtual"; type = "virtual";
hypervisorName = "atlas"; hypervisorName = "atlas";
isRaspberryPi = false;
isVirtualMachine = false;
isHypervisor = false;
nixosModule = { config, ... }: { nixosModule = { config, ... }: {
microvm.balloonMem = 7680; microvm.balloonMem = 7680;
@ -101,6 +135,9 @@
bancomart = { bancomart = {
type = "virtual"; type = "virtual";
hypervisorName = "jefke"; hypervisorName = "jefke";
isRaspberryPi = false;
isVirtualMachine = false;
isHypervisor = false;
nixosModule = { nixosModule = {
microvm.balloonMem = 7680; microvm.balloonMem = 7680;
@ -115,6 +152,9 @@
vpay = { vpay = {
type = "virtual"; type = "virtual";
hypervisorName = "lewis"; hypervisorName = "lewis";
isRaspberryPi = false;
isVirtualMachine = false;
isHypervisor = false;
nixosModule = { nixosModule = {
microvm.balloonMem = 5120; microvm.balloonMem = 5120;

View file

@ -22,11 +22,26 @@ in {
}; };
}; };
mainNicNamePattern = lib.mkOption { staticNetworking = lib.mkOption {
default = "en*"; default = false;
type = lib.types.bool;
description = ''
Whether this machine has static networking configuration applied.
Routing is prepopulated, but IP addresses have to be set.
'';
};
staticIPv4 = lib.mkOption {
type = lib.types.str; type = lib.types.str;
description = '' description = ''
Pattern to match the name of this machine's main NIC. Static IPv4 address for the machine.
'';
};
staticIPv6 = lib.mkOption {
type = lib.types.str;
description = ''
Static IPv6 address for the machine.
''; '';
}; };
}; };
@ -43,10 +58,10 @@ in {
}; };
}; };
systemd.network = lib.mkIf (machine.type == "physical") { systemd.network = {
enable = true; enable = true;
netdevs = { netdevs = lib.mkIf machine.isHypervisor {
"20-vlandmz" = { "20-vlandmz" = {
vlanConfig.Id = 30; vlanConfig.Id = 30;
@ -64,43 +79,89 @@ in {
}; };
}; };
networks = { networks = lib.attrsets.mergeAttrsList [
"30-main-nic" = { (lib.optionalAttrs machine.isHypervisor {
matchConfig.Name = cfg.mainNicNamePattern; "30-main-nic" = {
vlan = [ "vlandmz" ]; matchConfig.Name = "en*";
vlan = [ "vlandmz" ];
networkConfig = { networkConfig = {
DHCP = "yes"; DHCP = "yes";
};
}; };
};
"40-vlandmz" = { "40-vlandmz" = {
matchConfig.Name = "vlandmz"; matchConfig.Name = "vlandmz";
linkConfig.RequiredForOnline = "enslaved"; linkConfig.RequiredForOnline = "enslaved";
networkConfig = { networkConfig = {
IPv6AcceptRA = false; IPv6AcceptRA = false;
LinkLocalAddressing = "no"; LinkLocalAddressing = "no";
Bridge = cfg.dmz.bridgeName; Bridge = cfg.dmz.bridgeName;
};
}; };
};
"40-bridgedmz" = { "40-bridgedmz" = {
matchConfig.Name = cfg.dmz.bridgeName; matchConfig.Name = cfg.dmz.bridgeName;
linkConfig.RequiredForOnline = "carrier"; linkConfig.RequiredForOnline = "carrier";
networkConfig = { networkConfig = {
IPv6AcceptRA = cfg.dmz.allowConnectivity; IPv6AcceptRA = cfg.dmz.allowConnectivity;
LinkLocalAddressing = if cfg.dmz.allowConnectivity then "ipv6" else "no"; LinkLocalAddressing = if cfg.dmz.allowConnectivity then "ipv6" else "no";
DHCP = "yes"; DHCP = "yes";
};
}; };
};
"40-vms" = { "40-vms" = {
matchConfig.Name = "vm-*"; matchConfig.Name = "vm-*";
networkConfig.Bridge = cfg.dmz.bridgeName; networkConfig.Bridge = cfg.dmz.bridgeName;
}; };
}; })
(lib.optionalAttrs machine.isVirtualMachine {
"30-main-nic" = {
matchConfig.Name = "en*";
networkConfig = {
IPv6AcceptRA = ! cfg.staticNetworking;
DHCP = lib.mkIf (! cfg.staticNetworking) "yes";
Address = lib.mkIf cfg.staticNetworking [
"${cfg.staticIPv4}/${cfg.dmz.ipv4.prefixLength}"
"${cfg.staticIPv6}/${cfg.dmz.ipv6.prefixLength}"
];
DNS = lib.mkIf cfg.staticNetworking [
cfg.dmz.ipv4.router
cfg.dmz.ipv6.router
];
};
routes = lib.mkIf cfg.staticNetworking [
{
routeConfig = {
Gateway = cfg.dmz.ipv4.router;
Destination = "0.0.0.0/0";
};
}
{
routeConfig = {
Gateway = cfg.dmz.ipv6.router;
Destination = "::/0";
};
}
];
};
})
(lib.optionalAttrs machine.isRaspberryPi {
"30-main-nic" = {
matchConfig.Name = "end*";
networkConfig = {
IPv6AcceptRA = true;
DHCP = "yes";
};
};
})
];
}; };
}; };
} }

View file

@ -10,7 +10,8 @@ in {
}; };
dataPartition = lib.mkOption { dataPartition = lib.mkOption {
type = lib.types.str; default = null;
type = lib.types.nullOr lib.types.str;
description = '' description = ''
Partition to be used for data storage on this machine. Partition to be used for data storage on this machine.
''; '';
@ -25,38 +26,51 @@ in {
}; };
}; };
config = lib.mkIf (machine.type == "physical") { config = {
fileSystems.${cfg.dataMountPoint}.device = cfg.dataPartition; fileSystems = lib.attrsets.mergeAttrsList [
(lib.optionalAttrs machine.isHypervisor {
"${cfg.dataMountPoint}".device = cfg.dataPartition;
})
(lib.optionalAttrs machine.isRaspberryPi {
"/" = {
device = "/dev/disk/by-label/NIXOS_SD";
fsType = "ext4";
options = [ "noatime" ];
};
})
];
# 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.
disko.devices.disk.vdb = { disko = lib.mkIf machine.isHypervisor {
device = cfg.osDisk; devices.disk.vdb = {
type = "disk"; device = cfg.osDisk;
type = "disk";
content = { content = {
type = "gpt"; type = "gpt";
partitions = { partitions = {
swap.size = "100%"; swap.size = "100%";
ESP = { ESP = {
type = "EF00"; type = "EF00";
size = "500M"; size = "500M";
content = { content = {
type = "filesystem"; type = "filesystem";
format = "vfat"; format = "vfat";
mountpoint = "/boot"; mountpoint = "/boot";
};
}; };
};
root = { root = {
end = "-4G"; end = "-4G";
content = { content = {
type = "filesystem"; type = "filesystem";
format = "btrfs"; format = "btrfs";
mountpoint = "/"; mountpoint = "/";
};
}; };
}; };
}; };

View file

@ -1,11 +1,11 @@
{ pkgs, config, lib, modulesPath, microvm, disko, agenix, machines, dns, ... }: { { pkgs, config, lib, microvm, disko, agenix, machine, machines, dns, nixos-hardware, ... }: {
imports = [ imports = [
(modulesPath + "/installer/scan/not-detected.nix")
microvm.nixosModules.host microvm.nixosModules.host
]; ]
++ lib.lists.optional (machine.isRaspberryPi) nixos-hardware.nixosModules.raspberry-pi-4;
config = { config = {
boot = { boot = lib.mkIf (machine.isHypervisor) {
kernelModules = [ "kvm-intel" ]; kernelModules = [ "kvm-intel" ];
extraModulePackages = [ ]; extraModulePackages = [ ];
@ -30,10 +30,11 @@
nixpkgs = { nixpkgs = {
config.allowUnfree = true; config.allowUnfree = true;
hostPlatform = "x86_64-linux"; # TODO: do we need this?
# hostPlatform = machine.arch;
}; };
hardware.cpu.intel.updateMicrocode = config.hardware.enableRedistributableFirmware; hardware.cpu.intel.updateMicrocode = lib.mkIf (machine.isHypervisor) config.hardware.enableRedistributableFirmware;
age.identityPaths = [ "/etc/age_ed25519" ]; age.identityPaths = [ "/etc/age_ed25519" ];

View file

@ -2,6 +2,7 @@
imports = [ ./docker_swarm.nix ]; imports = [ ./docker_swarm.nix ];
options.lab.vm = { options.lab.vm = {
# TODO: make global.
baseMACAddress = lib.mkOption { baseMACAddress = lib.mkOption {
default = "BA:DB:EE:F0:00:00"; default = "BA:DB:EE:F0:00:00";
type = lib.types.str; type = lib.types.str;
@ -17,29 +18,6 @@
''; '';
}; };
staticNetworking = lib.mkOption {
default = false;
type = lib.types.bool;
description = ''
Whether this VM has static networking configuration applied.
Routing is prepopulated, but IP addresses have to be set.
'';
};
staticIPv4 = lib.mkOption {
type = lib.types.str;
description = ''
Static IPv4 address for the VM.
'';
};
staticIPv6 = lib.mkOption {
type = lib.types.str;
description = ''
Static IPv6 address for the VM.
'';
};
shares = lib.mkOption { shares = lib.mkOption {
default = [ ]; default = [ ];
description = '' description = ''
@ -73,16 +51,20 @@
mountPoint = "/etc/ssh/host_keys"; mountPoint = "/etc/ssh/host_keys";
}]; }];
services.openssh = { services.openssh =
hostKeys = [{ let
path = "/etc/ssh/host_keys/ssh_host_ed25519_key"; hostKeyPath = "/etc/ssh/host_keys/ssh_host_ed25519_key";
type = "ed25519"; in
}]; {
hostKeys = [{
path = hostKeyPath;
type = "ed25519";
}];
extraConfig = '' extraConfig = ''
HostKey /etc/ssh/host_keys/ssh_host_ed25519_key HostKey ${hostKeyPath}
''; '';
}; };
microvm = { microvm = {
# TODO: make this dependent on the host CPU # TODO: make this dependent on the host CPU
@ -108,51 +90,5 @@
mac = pkgs.lib.net.mac.add config.lab.vm.id config.lab.vm.baseMACAddress; mac = pkgs.lib.net.mac.add config.lab.vm.id config.lab.vm.baseMACAddress;
}]; }];
}; };
networking.useDHCP = false;
systemd.network =
let
cfg = config.lab.networking;
in
{
enable = true;
networks = {
"30-main-nic" = {
matchConfig.Name = "en*";
networkConfig = {
IPv6AcceptRA = ! config.lab.vm.staticNetworking;
DHCP = lib.mkIf (! config.lab.vm.staticNetworking) "yes";
Address = lib.mkIf config.lab.vm.staticNetworking [
"${ config.lab.vm.staticIPv4}/${cfg.dmz.ipv4.prefixLength}"
"${config.lab.vm.staticIPv6}/${cfg.dmz.ipv6.prefixLength}"
];
DNS = lib.mkIf config.lab.vm.staticNetworking [
cfg.dmz.ipv4.router
cfg.dmz.ipv6.router
];
};
routes = lib.mkIf config.lab.vm.staticNetworking [
{
routeConfig = {
Gateway = cfg.dmz.ipv4.router;
Destination = "0.0.0.0/0";
};
}
{
routeConfig = {
Gateway = cfg.dmz.ipv6.router;
Destination = "::/0";
};
}
];
};
};
};
}; };
} }