Initial networking VM
Also general improvements around VMs
This commit is contained in:
parent
5563d1be46
commit
009dec03cf
2
.envrc
2
.envrc
@ -1,2 +1,2 @@
|
|||||||
nix_direnv_watch_file devshell/{default,commands,install}.nix
|
nix_direnv_watch_file devshell/{default,commands,install,vm-tasks}.nix
|
||||||
use flake
|
use flake
|
||||||
|
@ -46,7 +46,13 @@ in
|
|||||||
name = "qemu-genmac";
|
name = "qemu-genmac";
|
||||||
category = "utilities";
|
category = "utilities";
|
||||||
help = "Generate MAC address suitable for QEMU";
|
help = "Generate MAC address suitable for QEMU";
|
||||||
command = ''printf "52:54:00:ab:%02x:%02x\n" $((RANDOM%256)) $((RANDOM%256))'';
|
command = ''printf "52:54:00:%02x:%02x:%02x\n" $((RANDOM%256)) $((RANDOM%256)) $((RANDOM%256))'';
|
||||||
|
}
|
||||||
|
{
|
||||||
|
name = "ssh-get-ed25519";
|
||||||
|
category = "utilities";
|
||||||
|
help = "Print the ed25519 pubkey for a host";
|
||||||
|
command = "${pkgs.openssh}/bin/ssh-keyscan -t ed25519 \"$1\" 2> /dev/null | awk '{ print $2 \" \" $3 }'";
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -3,7 +3,7 @@ let
|
|||||||
inherit (lib.my) attrsToNVList;
|
inherit (lib.my) attrsToNVList;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
imports = [ ./commands.nix ./install.nix ];
|
imports = [ ./commands.nix ./install.nix ./vm-tasks.nix ];
|
||||||
|
|
||||||
env = attrsToNVList {
|
env = attrsToNVList {
|
||||||
# starship will show this
|
# starship will show this
|
||||||
@ -13,6 +13,8 @@ in
|
|||||||
''
|
''
|
||||||
experimental-features = nix-command flakes ca-derivations
|
experimental-features = nix-command flakes ca-derivations
|
||||||
'');
|
'');
|
||||||
|
|
||||||
|
INSTALLER_SSH_OPTS = "-i .keys/deploy.key";
|
||||||
};
|
};
|
||||||
|
|
||||||
packages = with pkgs; [
|
packages = with pkgs; [
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
{ lib, pkgs, config, ... }:
|
{ lib, pkgs, config, ... }:
|
||||||
let
|
let
|
||||||
inherit (lib) mapAttrsToList concatMapStringsSep;
|
inherit (lib) mapAttrsToList;
|
||||||
inherit (lib.my) mkOpt' attrsToNVList;
|
inherit (lib.my) mkOpt';
|
||||||
|
|
||||||
parseArgs = opts:
|
parseArgs = opts:
|
||||||
''
|
''
|
||||||
@ -45,10 +45,10 @@ let
|
|||||||
log "[\e[36;1minfo\e[0m]: \e[36m$*\e[0m"
|
log "[\e[36;1minfo\e[0m]: \e[36m$*\e[0m"
|
||||||
}
|
}
|
||||||
warn() {
|
warn() {
|
||||||
log "[\e[33;1minfo\e[0m]: \e[33m$*\e[0m"
|
log "[\e[33;1mwarn\e[0m]: \e[33m$*\e[0m"
|
||||||
}
|
}
|
||||||
error() {
|
error() {
|
||||||
log "[\e[31;1minfo\e[0m]: \e[31m$*\e[0m"
|
log "[\e[31;1merror\e[0m]: \e[31m$*\e[0m"
|
||||||
}
|
}
|
||||||
die() {
|
die() {
|
||||||
error "$@"
|
error "$@"
|
||||||
|
128
devshell/vm-tasks.nix
Normal file
128
devshell/vm-tasks.nix
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
{ lib, pkgs, config, ... }:
|
||||||
|
let
|
||||||
|
inherit (lib) mapAttrsToList;
|
||||||
|
inherit (lib.my) mkOpt;
|
||||||
|
|
||||||
|
parseArgs = opts:
|
||||||
|
''
|
||||||
|
POSITIONAL_ARGS=()
|
||||||
|
|
||||||
|
while [ $# -gt 0 ]; do
|
||||||
|
# shellcheck disable=SC2221,SC2222
|
||||||
|
case $1 in
|
||||||
|
${opts}
|
||||||
|
-*|--*)
|
||||||
|
die "Unknown option $1"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
POSITIONAL_ARGS+=("$1") # save positional arg
|
||||||
|
shift # past argument
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
set -- "''${POSITIONAL_ARGS[@]}" # restore positional parameters
|
||||||
|
'';
|
||||||
|
common = pkgs.writeShellApplication {
|
||||||
|
name = "vm-tasks-common.sh";
|
||||||
|
runtimeInputs = with pkgs; [
|
||||||
|
openssh
|
||||||
|
];
|
||||||
|
text =
|
||||||
|
''
|
||||||
|
: "''${VM_SSH_OPTS:=}"
|
||||||
|
|
||||||
|
IFS=" " read -ra SSH_OPTS <<< "$VM_SSH_OPTS"
|
||||||
|
SSH_OPTS+=(-N)
|
||||||
|
|
||||||
|
HOST="''${1:-}"
|
||||||
|
VM="''${2:-}"
|
||||||
|
if [ -z "$HOST" ] || [ -z "$VM" ]; then
|
||||||
|
echo "usage: $0 <host> <vm> ..." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
SOCKS_DIR="$(mktemp -d --tmpdir vm-socks.XXXXXX)"
|
||||||
|
cleanup() {
|
||||||
|
rm -rf "$SOCKS_DIR"
|
||||||
|
}
|
||||||
|
trap cleanup EXIT
|
||||||
|
|
||||||
|
SOCKS=()
|
||||||
|
closeSocks() {
|
||||||
|
for p in "''${SOCK_PIDS[@]}"; do
|
||||||
|
kill "$p"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
openSock() {
|
||||||
|
local s="$SOCKS_DIR"/"$1".sock
|
||||||
|
ssh "''${SSH_OPTS[@]}" -L "$s":/run/vms/"$VM"/"$1".sock "$HOST" &
|
||||||
|
SOCKS+=($!)
|
||||||
|
echo "$s"
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
vmTaskOpts = with lib.types; {
|
||||||
|
options = {
|
||||||
|
help = mkOpt str null;
|
||||||
|
script = mkOpt lines "";
|
||||||
|
packages = mkOpt (listOf package) [ ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options.my.vmTasks = with lib.types;
|
||||||
|
mkOpt (attrsOf (submodule vmTaskOpts)) { };
|
||||||
|
|
||||||
|
config = {
|
||||||
|
my.vmTasks = {
|
||||||
|
vm-tty = {
|
||||||
|
help = "Access remote VM's TTY";
|
||||||
|
packages = with pkgs; [ minicom ];
|
||||||
|
script =
|
||||||
|
''
|
||||||
|
sock="$(openSock tty)"
|
||||||
|
minicom -D unix#"$sock"
|
||||||
|
closeSocks
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
vm-monitor = {
|
||||||
|
help = "Access remote VM's QEMU monitor";
|
||||||
|
packages = with pkgs; [ minicom ];
|
||||||
|
script =
|
||||||
|
''
|
||||||
|
sock="$(openSock monitor)"
|
||||||
|
minicom -D unix#"$sock"
|
||||||
|
closeSocks
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
vm-viewer = {
|
||||||
|
help = "Access remote VM's display with virt-viewer";
|
||||||
|
packages = with pkgs; [ virt-viewer ];
|
||||||
|
script =
|
||||||
|
''
|
||||||
|
sock=$(openSock spice)
|
||||||
|
remote-viewer spice+unix://"$sock"
|
||||||
|
closeSocks
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
commands = mapAttrsToList (name: cmd: {
|
||||||
|
inherit name;
|
||||||
|
inherit (cmd) help;
|
||||||
|
category = "vm-tasks";
|
||||||
|
package = pkgs.writeShellApplication {
|
||||||
|
inherit name;
|
||||||
|
runtimeInputs = cmd.packages;
|
||||||
|
text =
|
||||||
|
''
|
||||||
|
# shellcheck disable=SC1091
|
||||||
|
source "${common}/bin/vm-tasks-common.sh"
|
||||||
|
|
||||||
|
${cmd.script}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
}) config.my.vmTasks;
|
||||||
|
};
|
||||||
|
}
|
@ -95,6 +95,7 @@
|
|||||||
nixos/installer.nix
|
nixos/installer.nix
|
||||||
|
|
||||||
nixos/boxes/colony.nix
|
nixos/boxes/colony.nix
|
||||||
|
nixos/vms/estuary.nix
|
||||||
nixos/containers/vaultwarden.nix
|
nixos/containers/vaultwarden.nix
|
||||||
|
|
||||||
# Homes
|
# Homes
|
||||||
@ -138,7 +139,7 @@
|
|||||||
} //
|
} //
|
||||||
(eachDefaultSystem (system:
|
(eachDefaultSystem (system:
|
||||||
let
|
let
|
||||||
pkgs = pkgs'.unstable.${system};
|
pkgs = pkgs'.mine.${system};
|
||||||
lib = pkgs.lib;
|
lib = pkgs.lib;
|
||||||
in
|
in
|
||||||
# Stuff for each platform
|
# Stuff for each platform
|
||||||
|
@ -6,43 +6,112 @@
|
|||||||
|
|
||||||
configuration = { lib, pkgs, modulesPath, config, systems, ... }:
|
configuration = { lib, pkgs, modulesPath, config, systems, ... }:
|
||||||
let
|
let
|
||||||
inherit (lib) mkIf;
|
inherit (lib) mkIf mapAttrs;
|
||||||
|
|
||||||
|
wanBDF =
|
||||||
|
if config.my.build.isDevVM then "00:02.0" else "01:00.0";
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
imports = [ "${modulesPath}/profiles/qemu-guest.nix" ];
|
imports = [ "${modulesPath}/profiles/qemu-guest.nix" ];
|
||||||
|
|
||||||
|
boot.kernelParams = [ "intel_iommu=on" ];
|
||||||
|
boot.loader.systemd-boot.configurationLimit = 20;
|
||||||
|
fileSystems = {
|
||||||
|
"/boot" = {
|
||||||
|
device = "/dev/disk/by-label/ESP";
|
||||||
|
fsType = "vfat";
|
||||||
|
};
|
||||||
|
"/nix" = {
|
||||||
|
device = "/dev/ssds/colony-nix";
|
||||||
|
fsType = "ext4";
|
||||||
|
};
|
||||||
|
"/persist" = {
|
||||||
|
device = "/dev/ssds/colony-persist";
|
||||||
|
fsType = "ext4";
|
||||||
|
neededForBoot = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
services = {
|
||||||
|
lvm = {
|
||||||
|
boot.thin.enable = true;
|
||||||
|
dmeventd.enable = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
environment.systemPackages = with pkgs; [
|
||||||
|
pciutils
|
||||||
|
];
|
||||||
|
|
||||||
|
networking = {
|
||||||
|
interfaces = mkIf (!config.my.build.isDevVM) {
|
||||||
|
enp10s0.useDHCP = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd = {
|
||||||
|
network = {
|
||||||
|
netdevs."25-base-bridge".netdevConfig = {
|
||||||
|
Name = "base";
|
||||||
|
Kind = "bridge";
|
||||||
|
};
|
||||||
|
networks."80-base-bridge" = {
|
||||||
|
matchConfig = {
|
||||||
|
Name = "base";
|
||||||
|
Driver = "bridge";
|
||||||
|
};
|
||||||
|
DHCP = "ipv4";
|
||||||
|
networkConfig = {
|
||||||
|
IPv6AcceptRA = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
services."vm@estuary" = rec {
|
||||||
|
# Bind to the interface, networkd wait-online would deadlock...
|
||||||
|
requires = [ "sys-subsystem-net-devices-base.device" ];
|
||||||
|
bindsTo = requires;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
#environment.etc."udev/udev.conf".text = "udev_log=debug";
|
||||||
|
#systemd.services.systemd-networkd.environment.SYSTEMD_LOG_LEVEL = "debug";
|
||||||
|
virtualisation = {
|
||||||
|
cores = 8;
|
||||||
|
memorySize = 8192;
|
||||||
|
qemu.options = [
|
||||||
|
"-machine q35"
|
||||||
|
"-accel kvm,kernel-irqchip=split"
|
||||||
|
"-device intel-iommu,intremap=on,caching-mode=on"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
my = {
|
my = {
|
||||||
|
#deploy.generate.system.mode = "boot";
|
||||||
secrets = {
|
secrets = {
|
||||||
key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINkqdN5t3UKwrNOOPKlbnG1WYhnkV5H9luAzMotr8SbT";
|
key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKp5WDdDr/1NS3SJIDOKwcCNZDFOxqPAD7cbZWAP7EkX";
|
||||||
files."test.txt" = {};
|
files."test.txt" = {};
|
||||||
};
|
};
|
||||||
|
|
||||||
firewall = {
|
|
||||||
trustedInterfaces = [ "virtual" ];
|
|
||||||
nat = {
|
|
||||||
externalInterface = "eth0";
|
|
||||||
forwardPorts = [
|
|
||||||
{
|
|
||||||
proto = "tcp";
|
|
||||||
sourcePort = 2222;
|
|
||||||
destination = "127.0.0.1:22";
|
|
||||||
}
|
|
||||||
];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
server.enable = true;
|
server.enable = true;
|
||||||
|
|
||||||
containers = {
|
network = {
|
||||||
instances.vaultwarden = {
|
ipv6 = "2a0e:97c0:4d1:0::2";
|
||||||
networking.bridge = "virtual";
|
ipv4 = "10.110.0.2";
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
firewall = {
|
||||||
|
trustedInterfaces = [ "base" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
#containers = {
|
||||||
|
# instances.vaultwarden = {
|
||||||
|
# networking.bridge = "virtual";
|
||||||
|
# };
|
||||||
|
#};
|
||||||
vms = {
|
vms = {
|
||||||
instances.test = {
|
instances.estuary = {
|
||||||
uuid = "59f51efb-7e6d-477b-a263-ed9620dbc87b";
|
uuid = "59f51efb-7e6d-477b-a263-ed9620dbc87b";
|
||||||
networks.virtual.mac = "52:54:00:ab:f1:52";
|
networks.base.mac = "52:54:00:ab:f1:52";
|
||||||
drives = {
|
drives = {
|
||||||
disk = {
|
installer = {
|
||||||
backend = {
|
backend = {
|
||||||
driver = "file";
|
driver = "file";
|
||||||
filename = "${systems.installer.configuration.config.my.buildAs.iso}/iso/nixos.iso";
|
filename = "${systems.installer.configuration.config.my.buildAs.iso}/iso/nixos.iso";
|
||||||
@ -50,62 +119,31 @@
|
|||||||
};
|
};
|
||||||
format.driver = "raw";
|
format.driver = "raw";
|
||||||
frontend = "ide-cd";
|
frontend = "ide-cd";
|
||||||
|
frontendOpts = {
|
||||||
|
bootindex = 1;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
disk = {
|
||||||
|
backend = {
|
||||||
|
driver = "host_device";
|
||||||
|
filename = "/dev/ssds/vm-estuary";
|
||||||
|
# It appears this needs to be set on the backend _and_ the format
|
||||||
|
discard = "unmap";
|
||||||
|
};
|
||||||
|
format = {
|
||||||
|
driver = "raw";
|
||||||
|
discard = "unmap";
|
||||||
|
};
|
||||||
|
frontend = "virtio-blk";
|
||||||
frontendOpts = {
|
frontendOpts = {
|
||||||
bootindex = 0;
|
bootindex = 0;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
hostDevices."${wanBDF}" = { };
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
fileSystems = {
|
|
||||||
"/boot" = {
|
|
||||||
device = "/dev/disk/by-label/ESP";
|
|
||||||
fsType = "vfat";
|
|
||||||
};
|
|
||||||
"/nix" = {
|
|
||||||
device = "/dev/disk/by-label/nix";
|
|
||||||
fsType = "ext4";
|
|
||||||
};
|
|
||||||
"/persist" = {
|
|
||||||
device = "/dev/disk/by-label/persist";
|
|
||||||
fsType = "ext4";
|
|
||||||
neededForBoot = true;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
networking = {
|
|
||||||
interfaces = mkIf (!config.my.build.isDevVM) {
|
|
||||||
enp1s0.useDHCP = true;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
systemd.network = {
|
|
||||||
netdevs."25-virtual-bridge".netdevConfig = {
|
|
||||||
Name = "virtual";
|
|
||||||
Kind = "bridge";
|
|
||||||
};
|
|
||||||
networks."80-virtual-bridge" = {
|
|
||||||
matchConfig = {
|
|
||||||
Name = "virtual";
|
|
||||||
Driver = "bridge";
|
|
||||||
};
|
|
||||||
networkConfig = {
|
|
||||||
Address = "172.16.137.1/24";
|
|
||||||
DHCPServer = true;
|
|
||||||
# TODO: Configuration for routed IPv6 (and maybe IPv4)
|
|
||||||
IPMasquerade = "both";
|
|
||||||
IPv6SendRA = true;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
#systemd.services.systemd-networkd.environment.SYSTEMD_LOG_LEVEL = "debug";
|
|
||||||
virtualisation = {
|
|
||||||
cores = 8;
|
|
||||||
memorySize = 8192;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -13,14 +13,14 @@
|
|||||||
in
|
in
|
||||||
{
|
{
|
||||||
imports = [
|
imports = [
|
||||||
# Lots of kernel modules and firmware
|
|
||||||
"${modulesPath}/profiles/all-hardware.nix"
|
|
||||||
# Useful tools to have
|
# Useful tools to have
|
||||||
"${modulesPath}/profiles/base.nix"
|
"${modulesPath}/profiles/base.nix"
|
||||||
];
|
];
|
||||||
|
|
||||||
config = {
|
config = {
|
||||||
my = {
|
my = {
|
||||||
|
# Lots of kernel modules and firmware
|
||||||
|
build.allHardware = true;
|
||||||
# Whatever installer mechanism is chosen will provide an appropriate `/`
|
# Whatever installer mechanism is chosen will provide an appropriate `/`
|
||||||
tmproot.enable = false;
|
tmproot.enable = false;
|
||||||
firewall.nat.enable = false;
|
firewall.nat.enable = false;
|
||||||
@ -72,9 +72,6 @@
|
|||||||
'';
|
'';
|
||||||
|
|
||||||
environment.systemPackages = with pkgs; [
|
environment.systemPackages = with pkgs; [
|
||||||
# We disable networking.useDHCP, so bring these in for the user
|
|
||||||
# dhcpcd probably has more features, but dhclient actually seems a bit more simple
|
|
||||||
(pkgs.writeShellScriptBin "dhclient" ''exec ${pkgs.dhcp}/bin/dhclient -v "$@"'')
|
|
||||||
dhcpcd
|
dhcpcd
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -99,6 +96,7 @@
|
|||||||
# download-using-manifests.pl from forking even if there is
|
# download-using-manifests.pl from forking even if there is
|
||||||
# plenty of free memory.
|
# plenty of free memory.
|
||||||
boot.kernel.sysctl."vm.overcommit_memory" = "1";
|
boot.kernel.sysctl."vm.overcommit_memory" = "1";
|
||||||
|
services.lvm.boot.thin.enable = true;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -11,5 +11,6 @@
|
|||||||
secrets = ./secrets.nix;
|
secrets = ./secrets.nix;
|
||||||
containers = ./containers.nix;
|
containers = ./containers.nix;
|
||||||
vms = ./vms.nix;
|
vms = ./vms.nix;
|
||||||
|
network = ./network.nix;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -80,6 +80,7 @@ in
|
|||||||
sharedDirectories = dummyOption;
|
sharedDirectories = dummyOption;
|
||||||
cores = dummyOption;
|
cores = dummyOption;
|
||||||
memorySize = dummyOption;
|
memorySize = dummyOption;
|
||||||
|
qemu.options = dummyOption;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{ lib, pkgs, pkgs', inputs, config, ... }:
|
{ lib, pkgs, pkgs', inputs, config, ... }:
|
||||||
let
|
let
|
||||||
inherit (lib) flatten optional mkIf mkDefault mkMerge;
|
inherit (lib) mkIf mkDefault mkMerge;
|
||||||
inherit (lib.my) mkBoolOpt' dummyOption;
|
inherit (lib.my) mkBoolOpt' dummyOption;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
@ -95,17 +95,11 @@ in
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
networking = {
|
|
||||||
domain = mkDefault "int.nul.ie";
|
|
||||||
useDHCP = false;
|
|
||||||
enableIPv6 = mkDefault true;
|
|
||||||
useNetworkd = mkDefault true;
|
|
||||||
};
|
|
||||||
|
|
||||||
environment.systemPackages = with pkgs; [
|
environment.systemPackages = with pkgs; [
|
||||||
bash-completion
|
bash-completion
|
||||||
vim
|
vim
|
||||||
ldns
|
ldns
|
||||||
|
minicom
|
||||||
];
|
];
|
||||||
|
|
||||||
programs = {
|
programs = {
|
||||||
@ -141,14 +135,6 @@ in
|
|||||||
})
|
})
|
||||||
];
|
];
|
||||||
})
|
})
|
||||||
(mkIf config.my.build.isDevVM {
|
|
||||||
networking.interfaces.eth0.useDHCP = mkDefault true;
|
|
||||||
virtualisation = {
|
|
||||||
forwardPorts = flatten [
|
|
||||||
(optional config.services.openssh.openFirewall { from = "host"; host.port = 2222; guest.port = 22; })
|
|
||||||
];
|
|
||||||
};
|
|
||||||
})
|
|
||||||
];
|
];
|
||||||
|
|
||||||
meta.buildDocsInSandbox = false;
|
meta.buildDocsInSandbox = false;
|
||||||
|
@ -1,11 +1,24 @@
|
|||||||
{ lib, pkgs, config, systems, ... }:
|
{ lib, pkgs, config, systems, ... }:
|
||||||
let
|
let
|
||||||
inherit (builtins) head attrNames;
|
inherit (builtins) head attrNames;
|
||||||
inherit (lib) mkMerge mkIf mkDefault optionalAttrs mapAttrs';
|
inherit (lib) mkMerge mkIf mkDefault optionalAttrs mapAttrs' optionalString;
|
||||||
inherit (lib.my) mkOpt' mkBoolOpt';
|
inherit (lib.my) mkOpt' mkBoolOpt';
|
||||||
|
|
||||||
cfg = config.my.deploy;
|
cfg = config.my.deploy;
|
||||||
|
|
||||||
|
# Based on https://github.com/serokell/deploy-rs/blob/master/flake.nix
|
||||||
|
nixosActivate = mode: base: (pkgs.deploy-rs.lib.activate.custom // { dryActivate = "$PROFILE/bin/switch-to-configuration dry-activate"; }) base.config.system.build.toplevel ''
|
||||||
|
# work around https://github.com/NixOS/nixpkgs/issues/73404
|
||||||
|
cd /tmp
|
||||||
|
|
||||||
|
$PROFILE/bin/switch-to-configuration ${mode}
|
||||||
|
|
||||||
|
# https://github.com/serokell/deploy-rs/issues/31
|
||||||
|
${with base.config.boot.loader;
|
||||||
|
optionalString ((mode == "switch" || mode == "boot") && systemd-boot.enable)
|
||||||
|
"sed -i '/^default /d' ${efi.efiSysMountPoint}/loader/loader.conf"}
|
||||||
|
'';
|
||||||
|
|
||||||
ctrProfiles = optionalAttrs cfg.generate.containers.enable (mapAttrs' (n: c:
|
ctrProfiles = optionalAttrs cfg.generate.containers.enable (mapAttrs' (n: c:
|
||||||
let
|
let
|
||||||
ctrConfig = systems."${n}".configuration.config;
|
ctrConfig = systems."${n}".configuration.config;
|
||||||
@ -34,7 +47,10 @@ in
|
|||||||
inherit (lib.my.deploy-rs) node;
|
inherit (lib.my.deploy-rs) node;
|
||||||
|
|
||||||
generate = {
|
generate = {
|
||||||
system.enable = mkBoolOpt' true "Whether to generate a deploy-rs profile for this system's config.";
|
system = {
|
||||||
|
enable = mkBoolOpt' true "Whether to generate a deploy-rs profile for this system's config.";
|
||||||
|
mode = mkOpt' str "switch" "switch-to-configuration mode.";
|
||||||
|
};
|
||||||
containers.enable = mkBoolOpt' true "Whether to generate deploy-rs profiles for this system's containers.";
|
containers.enable = mkBoolOpt' true "Whether to generate deploy-rs profiles for this system's containers.";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@ -49,7 +65,7 @@ in
|
|||||||
profilesOrder = [ "system" ] ++ (attrNames ctrProfiles);
|
profilesOrder = [ "system" ] ++ (attrNames ctrProfiles);
|
||||||
profiles = {
|
profiles = {
|
||||||
system = mkIf cfg.generate.system.enable {
|
system = mkIf cfg.generate.system.enable {
|
||||||
path = pkgs.deploy-rs.lib.activate.nixos { inherit config; };
|
path = nixosActivate cfg.generate.system.mode { inherit config; };
|
||||||
|
|
||||||
user = "root";
|
user = "root";
|
||||||
};
|
};
|
||||||
|
35
nixos/modules/network.nix
Normal file
35
nixos/modules/network.nix
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
{ lib, config, ... }:
|
||||||
|
let
|
||||||
|
inherit (lib) flatten optional mkIf mkDefault mkMerge;
|
||||||
|
inherit (lib.my) mkOpt' mkBoolOpt';
|
||||||
|
|
||||||
|
cfg = config.my.network;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options = with lib.types; {
|
||||||
|
my.network = {
|
||||||
|
ipv4 = mkOpt' str null "Internal network IPv4 address.";
|
||||||
|
ipv6 = mkOpt' str null "Internal network IPv6 address.";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkMerge [
|
||||||
|
{
|
||||||
|
networking = {
|
||||||
|
domain = mkDefault "int.nul.ie";
|
||||||
|
useDHCP = false;
|
||||||
|
enableIPv6 = mkDefault true;
|
||||||
|
useNetworkd = mkDefault true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
(mkIf config.my.build.isDevVM {
|
||||||
|
networking.interfaces.eth0.useDHCP = mkDefault true;
|
||||||
|
virtualisation = {
|
||||||
|
forwardPorts = flatten [
|
||||||
|
(optional config.services.openssh.openFirewall { from = "host"; host.port = 2222; guest.port = 22; })
|
||||||
|
];
|
||||||
|
};
|
||||||
|
})
|
||||||
|
];
|
||||||
|
}
|
@ -22,15 +22,14 @@ in
|
|||||||
# agenix sets this as a default but adding any custom extras will _replace_ the list (different priority)
|
# agenix sets this as a default but adding any custom extras will _replace_ the list (different priority)
|
||||||
identityPaths =
|
identityPaths =
|
||||||
mkIf config.services.openssh.enable
|
mkIf config.services.openssh.enable
|
||||||
(map (e: e.path) (lib.filter (e: e.type == "rsa" || e.type == "ed25519") config.services.openssh.hostKeys));
|
(map
|
||||||
|
# Use the persit dir to grab the keys instead, otherwise they might not be ready. We can't really make
|
||||||
|
# agenix depend on impermanence, since users depends on agenix (to decrypt passwords) and impermanence
|
||||||
|
# depends on users
|
||||||
|
(e: let pDir = config.my.tmproot.persistence.dir; in if pDir != null then "${pDir}/${e.path}" else e.path)
|
||||||
|
(lib.filter (e: e.type == "rsa" || e.type == "ed25519") config.services.openssh.hostKeys));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
(mkIf (config.age.secrets != { }) {
|
|
||||||
system.activationScripts.agenixMountSecrets.deps = mkIf (config.my.tmproot.persistence.dir != null) [
|
|
||||||
# The key used to decrypt is not going to exist!
|
|
||||||
"persist-files"
|
|
||||||
];
|
|
||||||
})
|
|
||||||
(mkIf config.my.build.isDevVM {
|
(mkIf config.my.build.isDevVM {
|
||||||
age.identityPaths = [ cfg.vmKeyPath ];
|
age.identityPaths = [ cfg.vmKeyPath ];
|
||||||
})
|
})
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
{ lib, pkgs, config, ... }:
|
{ lib, pkgs, config, ... }:
|
||||||
let
|
let
|
||||||
inherit (lib) optional optionals optionalString flatten concatStringsSep mapAttrsToList mapAttrs' mkIf mkDefault;
|
inherit (builtins) filter any attrNames attrValues fetchGit;
|
||||||
|
inherit (lib)
|
||||||
|
unique optional optionals optionalString flatten concatStringsSep
|
||||||
|
concatMapStringsSep mapAttrsToList mapAttrs' mkIf mkDefault;
|
||||||
inherit (lib.my) mkOpt' mkBoolOpt';
|
inherit (lib.my) mkOpt' mkBoolOpt';
|
||||||
|
|
||||||
flattenQEMUOpts = attrs:
|
flattenQEMUOpts = attrs:
|
||||||
@ -38,6 +41,29 @@ let
|
|||||||
pass
|
pass
|
||||||
'';
|
'';
|
||||||
|
|
||||||
|
# TODO: Upstream or something...
|
||||||
|
vfio-pci-bind = pkgs.stdenv.mkDerivation rec {
|
||||||
|
pname = "vfio-pci-bind";
|
||||||
|
version = "b41e4545b21de434fc51a34a9bf1d72e3ac66cc8";
|
||||||
|
|
||||||
|
src = fetchGit {
|
||||||
|
url = "https://github.com/andre-richter/vfio-pci-bind";
|
||||||
|
rev = version;
|
||||||
|
};
|
||||||
|
|
||||||
|
prePatch = ''
|
||||||
|
substituteInPlace vfio-pci-bind.sh \
|
||||||
|
--replace modprobe ${pkgs.kmod}/bin/modprobe
|
||||||
|
substituteInPlace 25-vfio-pci-bind.rules \
|
||||||
|
--replace vfio-pci-bind.sh "$out"/bin/vfio-pci-bind.sh
|
||||||
|
'';
|
||||||
|
installPhase = ''
|
||||||
|
mkdir -p "$out"/bin/ "$out"/lib/udev/rules.d
|
||||||
|
cp vfio-pci-bind.sh "$out"/bin/
|
||||||
|
cp 25-vfio-pci-bind.rules "$out"/lib/udev/rules.d/
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
cfg = config.my.vms;
|
cfg = config.my.vms;
|
||||||
|
|
||||||
netOpts = with lib.types; { name, ... }: {
|
netOpts = with lib.types; { name, ... }: {
|
||||||
@ -61,6 +87,12 @@ let
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
hostDevOpts = with lib.types; {
|
||||||
|
options = {
|
||||||
|
bindVFIO = mkBoolOpt' true "Whether to automatically bind the device to vfio-pci.";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
vmOpts = with lib.types; { name, ... }: {
|
vmOpts = with lib.types; { name, ... }: {
|
||||||
options = {
|
options = {
|
||||||
qemuBin = mkOpt' path "${pkgs.qemu_kvm}/bin/qemu-kvm" "Path to QEMU executable.";
|
qemuBin = mkOpt' path "${pkgs.qemu_kvm}/bin/qemu-kvm" "Path to QEMU executable.";
|
||||||
@ -85,9 +117,16 @@ let
|
|||||||
spice.enable = mkBoolOpt' true "Whether to enable SPICE.";
|
spice.enable = mkBoolOpt' true "Whether to enable SPICE.";
|
||||||
networks = mkOpt' (attrsOf (submodule netOpts)) { } "Networks to attach VM to.";
|
networks = mkOpt' (attrsOf (submodule netOpts)) { } "Networks to attach VM to.";
|
||||||
drives = mkOpt' (attrsOf (submodule driveOpts)) { } "Drives to attach to VM.";
|
drives = mkOpt' (attrsOf (submodule driveOpts)) { } "Drives to attach to VM.";
|
||||||
|
hostDevices = mkOpt' (attrsOf (submodule hostDevOpts)) { } "Host PCI devices to pass to the VM.";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
allHostDevs =
|
||||||
|
flatten
|
||||||
|
(map
|
||||||
|
(i: mapAttrsToList (bdf: c: { inherit bdf; inherit (c) bindVFIO; }) i.hostDevices)
|
||||||
|
(attrValues cfg.instances));
|
||||||
|
|
||||||
mkQemuCommand = n: i:
|
mkQemuCommand = n: i:
|
||||||
let
|
let
|
||||||
flags =
|
flags =
|
||||||
@ -122,7 +161,8 @@ let
|
|||||||
"blockdev node-name=${dn}-backend,${c.backend}"
|
"blockdev node-name=${dn}-backend,${c.backend}"
|
||||||
"blockdev node-name=${dn}-format,${c.formatBackendProp}=${dn}-backend,${c.format}"
|
"blockdev node-name=${dn}-format,${c.formatBackendProp}=${dn}-backend,${c.format}"
|
||||||
("device ${c.frontend},id=${dn},drive=${dn}-format" + (extraQEMUOpts c.frontendOpts))
|
("device ${c.frontend},id=${dn},drive=${dn}-format" + (extraQEMUOpts c.frontendOpts))
|
||||||
]) i.drives));
|
]) i.drives)) ++
|
||||||
|
(map (bdf: "device vfio-pci,host=${bdf}") (attrNames i.hostDevices));
|
||||||
args = map (v: "-${v}") flags;
|
args = map (v: "-${v}") flags;
|
||||||
in
|
in
|
||||||
concatStringsSep " " ([ i.qemuBin ] ++ args);
|
concatStringsSep " " ([ i.qemuBin ] ++ args);
|
||||||
@ -134,6 +174,30 @@ in
|
|||||||
};
|
};
|
||||||
|
|
||||||
config = mkIf (cfg.instances != { }) {
|
config = mkIf (cfg.instances != { }) {
|
||||||
|
assertions = [
|
||||||
|
{
|
||||||
|
assertion = let bdfs = map (d: d.bdf) allHostDevs; in (unique bdfs) == bdfs;
|
||||||
|
message = "VMs cannot share host devices!";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
services.udev = {
|
||||||
|
packages =
|
||||||
|
optionals
|
||||||
|
(any (d: d.bindVFIO) allHostDevs)
|
||||||
|
[
|
||||||
|
vfio-pci-bind
|
||||||
|
(pkgs.writeTextDir
|
||||||
|
"etc/udev/rules.d/20-vfio-tags.rules"
|
||||||
|
(concatMapStringsSep
|
||||||
|
"\n"
|
||||||
|
(d: ''ACTION=="add", SUBSYSTEM=="pci", KERNEL=="0000:${d.bdf}", TAG="vfio-pci-bind"'')
|
||||||
|
(filter (d: d.bindVFIO) allHostDevs)))
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
my.tmproot.persistence.config.directories = [ "/var/lib/vms" ];
|
||||||
|
|
||||||
# qemu-bridge-helper will fail otherwise
|
# qemu-bridge-helper will fail otherwise
|
||||||
environment.etc."qemu/bridge.conf".text = "allow all";
|
environment.etc."qemu/bridge.conf".text = "allow all";
|
||||||
systemd = {
|
systemd = {
|
||||||
|
101
nixos/vms/estuary.nix
Normal file
101
nixos/vms/estuary.nix
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
{
|
||||||
|
nixos.systems.estuary = {
|
||||||
|
system = "x86_64-linux";
|
||||||
|
nixpkgs = "mine";
|
||||||
|
home-manager = "unstable";
|
||||||
|
|
||||||
|
configuration = { lib, pkgs, modulesPath, config, systems, ... }:
|
||||||
|
let
|
||||||
|
inherit (lib) mkIf mkMerge;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
imports = [ "${modulesPath}/profiles/qemu-guest.nix" ];
|
||||||
|
|
||||||
|
config = mkMerge [
|
||||||
|
{
|
||||||
|
boot.kernelParams = [ "console=ttyS0,115200n8" ];
|
||||||
|
fileSystems = {
|
||||||
|
"/boot" = {
|
||||||
|
device = "/dev/disk/by-label/ESP";
|
||||||
|
fsType = "vfat";
|
||||||
|
};
|
||||||
|
"/nix" = {
|
||||||
|
device = "/dev/main/nix";
|
||||||
|
fsType = "ext4";
|
||||||
|
};
|
||||||
|
"/persist" = {
|
||||||
|
device = "/dev/main/persist";
|
||||||
|
fsType = "ext4";
|
||||||
|
neededForBoot = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
services = {
|
||||||
|
lvm = {
|
||||||
|
dmeventd.enable = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.network = {
|
||||||
|
links = {
|
||||||
|
"10-wan" = {
|
||||||
|
matchConfig.MACAddress = "52:54:00:a1:b2:5f";
|
||||||
|
linkConfig.Name = "wan";
|
||||||
|
};
|
||||||
|
"10-base" = {
|
||||||
|
matchConfig.MACAddress = "52:54:00:ab:f1:52";
|
||||||
|
linkConfig.Name = "base";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
networks = {
|
||||||
|
#"80-wan" = {
|
||||||
|
# matchConfig.Name = "wan";
|
||||||
|
# address = [
|
||||||
|
# "1.2.3.4/24"
|
||||||
|
# "2a00::2/64"
|
||||||
|
# ];
|
||||||
|
#};
|
||||||
|
"80-wan" = {
|
||||||
|
matchConfig.Name = "wan";
|
||||||
|
DHCP = "ipv4";
|
||||||
|
};
|
||||||
|
"80-base" = {
|
||||||
|
matchConfig.Name = "base";
|
||||||
|
address = with config.my.network; [ "${ipv4}/24" "${ipv6}/64" ];
|
||||||
|
networkConfig = {
|
||||||
|
DHCPServer = true;
|
||||||
|
IPv6SendRA = true;
|
||||||
|
IPMasquerade = "both";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
my = {
|
||||||
|
server.enable = true;
|
||||||
|
|
||||||
|
network = {
|
||||||
|
ipv6 = "2a0e:97c0:4d1:0::1";
|
||||||
|
ipv4 = "10.110.0.1";
|
||||||
|
};
|
||||||
|
firewall = {
|
||||||
|
trustedInterfaces = [ "base" ];
|
||||||
|
nat = {
|
||||||
|
enable = true;
|
||||||
|
externalInterface = "wan";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
(mkIf config.my.build.isDevVM {
|
||||||
|
systemd.network = {
|
||||||
|
netdevs."05-dummy-base".netdevConfig = {
|
||||||
|
Name = "base";
|
||||||
|
Kind = "dummy";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
})
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue
Block a user