From 429f846f9b2558e2926da5f671735a119f65001f Mon Sep 17 00:00:00 2001 From: James Andariese Date: Mon, 26 Sep 2022 07:27:59 -0600 Subject: [PATCH] updates to make morph transparently available when building images --- README.md | 75 ++++++++++++++++++++++++++++++++++++ custom-image.nix | 4 +- hosts/.gitignore | 3 ++ hosts/_basic.nix | 6 ++- hosts/default.nix | 10 ++++- network.nix | 3 +- profiles/api/default.nix | 2 +- profiles/base/default.nix | 16 ++++++++ profiles/qemu-vm/default.nix | 10 ++--- shell.nix | 19 +++++---- 10 files changed, 125 insertions(+), 23 deletions(-) create mode 100644 hosts/.gitignore mode change 100755 => 100644 shell.nix diff --git a/README.md b/README.md index 51dff63..a4d9f85 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,81 @@ In order to discover your network and configure hosts, this configuration manage * Proxmox running on the local host * Proxmox should have a local filesystem called hdd-fs +## The Future (or how to not Proxmox) + +### Or how it works without the script + +Proxmox is not _at all_ a requirement for using this. + +Neither is Samba. They are requirements for the mkvirt function in shell.nix. + +This may be replaced or not used at all. The image created in result/nixos.img will boot on most hypervisors. + +After the image is created and booted, it must be morphed. + +The first step in morphing is making the machine resolveable. This is done with Samba but may be done with +another DNS system. The key is that it must be resolveable _immediately_ after the record is created because +morph then uses that record to find the machine. Reworking this to use IPs would require changing morph's +defaults or explicitly setting the deployment target address to be something other than the hostname. + +After the host is resolveable, morph. + +### Interesting Places + +* `custom-image.nix` + * nixos.img disk size, format, partition table, etc +* `common/ssh.nix` + * configure ssh package (such as `openssh_gssapi` vs `openssh`) +* `common/users.nix` + * the deploy user, ssh keys, shell, etc. +* `functions/*.nix` + * a function per file + * load default.nix to load all functions by name in a set +* `hosts/*` + * hosts deployed via morph are pulled from here automatically + * files in this folder should be informational only. they _do not_ return a function. + * functionality which requires access to config or pkgs should be implemented in `profiles/` and loaded by name in imports. +* `profiles/*` + * profiles for describing machines of a certain class. + * profiles may represent hardware such as `api` and `qemu-vm` or a configuration pattern such as `dhcp-server` or `base`. + * the `base` profile is special in that it _should_ always be loaded. it is generally included by the hardware profile. +* `shell.nix` + * shell functions and configuration to build and deploy machines + * `env_cascade` + * discover domain, and realm config such as domain controller (samba) to send DNS updates to + * sanitize config + * returns env vars + * `$DOMAIN` + * domain name (from hostname -d), lowercase + * `$REALM` + * domain name (from hostname -d), uppercase + * `$workgroup` + * workgroup (first domain segment), lowercase + * `$WORKGROUP` + * workgroup (first domain segment), uppercase + * `$DC` + * lookup PTR of (lookup A of $DOMAIN) + * this will find a domain controller in a "normal" domain such as is created by default in Samba + * `env_name` + * sanitize hostname + * returns env vars + * `$name` hostname, lowercase + * `$NAME` hostname, uppercase + * `samba-create-ipv4-records` + * create DNS records + * `wait-for-vm-ipv4` + * wait for a VM to have an ipv4 address in a private subnet + * `mkvirt` + * `morph build` + * get an unused VMID from Proxmox + * create a new virt with discovered VMID + * wait for IP + * create DNS record with IP + * morph deploy to single machine + * `destroy-host` + * removes hosts/$name.nix + * removes DNS entry for $name.$DOMAIN + NIX: https://www.nixos.org PVE: https://www.proxmox.com/en/proxmox-ve diff --git a/custom-image.nix b/custom-image.nix index 15a9342..5dad38a 100644 --- a/custom-image.nix +++ b/custom-image.nix @@ -1,6 +1,8 @@ +with builtins; + {}: let - myisoconfig = import ./custom-image-configuration.nix; + myisoconfig = import ./hosts/_basic.nix; copyChannel = true; system = "x86_64-linux"; diff --git a/hosts/.gitignore b/hosts/.gitignore new file mode 100644 index 0000000..f9f4b19 --- /dev/null +++ b/hosts/.gitignore @@ -0,0 +1,3 @@ +*.nix +!_*.nix +!default.nix diff --git a/hosts/_basic.nix b/hosts/_basic.nix index 1aa2571..6381be9 100644 --- a/hosts/_basic.nix +++ b/hosts/_basic.nix @@ -1,8 +1,10 @@ -{ nodes, config, pkgs, ... }: { +{ imports = [ (toString ../profiles/qemu-vm) ]; config = { - deployment.tags = [ ]; + #deployment.targetHost = ""; + #deployment.targetUser = ""; + #deployment.targetPort = ""; }; } diff --git a/hosts/default.nix b/hosts/default.nix index e439f1a..fb88604 100644 --- a/hosts/default.nix +++ b/hosts/default.nix @@ -2,4 +2,12 @@ let _ = builtins.trace "${toString ./.}/default.nix"; in with builtins; with import (toString ../functions); -import-folder {path = "${toString ./.}"; filenameMatch = ".*[.]nix"; filenameBadMatch = ".*_.*";} +let hosts = import-folder {path = "${toString ./.}"; filenameMatch = ".*[.]nix"; filenameBadMatch = ".*_.*";}; +in + +{...}: +mapAttrs (hostname: hostdef: + +{...}: hostdef + +) hosts diff --git a/network.nix b/network.nix index eee1a40..b1e108e 100644 --- a/network.nix +++ b/network.nix @@ -1,11 +1,12 @@ with builtins; +with import ./functions; let pkgs = import {}; network = { inherit pkgs; description = "cascade"; }; - hosts = import (toString ./hosts); + hosts = import (toString ./hosts) {}; in hosts // { diff --git a/profiles/api/default.nix b/profiles/api/default.nix index 7f631a1..be4de35 100644 --- a/profiles/api/default.nix +++ b/profiles/api/default.nix @@ -7,7 +7,7 @@ imports = [ (toString ../base) ]; config = { - deployment.targetUser = "root"; + deployment.targetUser = lib.mkDefault "root"; boot.initrd.availableKernelModules = [ "xhci_pci" "dwc3_pci" "usbhid" "usb_storage" "uas" "sd_mod" "sdhci_acpi" ]; boot.initrd.kernelModules = [ ]; boot.kernelModules = [ "kvm-intel" ]; diff --git a/profiles/base/default.nix b/profiles/base/default.nix index 03e1c1f..eb4612e 100644 --- a/profiles/base/default.nix +++ b/profiles/base/default.nix @@ -2,13 +2,29 @@ { imports = [ (toString ../../common) + # we include the options here to ensure that we can build with or without morph. + # morph-lib must be NIX_PATH and point to the lib path of the morph that is being + # used for deployment. This is done automatically with shell.nix. ]; config = { environment.systemPackages = with pkgs; [ bridge-utils ]; programs.neovim.enable = true; programs.neovim.vimAlias = true; programs.neovim.viAlias = true; + + environment.binbash.enable = true; + + services.getty.autologinUser = "root"; + + services.sshd.enable = true; + networking.firewall.allowedTCPPorts = [ 22 ]; system.stateVersion = "22.11"; + + nix.nixPath = with pkgs; [ + "nixpkgs=/usr/src/nixpkgs" + "home-manager=/usr/src/nixpkgs" + "morph-options=${morph.lib}/options.nix" + ]; }; } diff --git a/profiles/qemu-vm/default.nix b/profiles/qemu-vm/default.nix index 22580d6..1169f84 100644 --- a/profiles/qemu-vm/default.nix +++ b/profiles/qemu-vm/default.nix @@ -1,11 +1,12 @@ -{lib, ...}: +{lib, config, ...}: with lib; { imports = [ (toString ../base) ]; config = { - deployment.targetUser = "root"; + deployment.targetUser = lib.mkDefault "root"; + cascade.bridge-interface = "ens18"; fileSystems."/" = { device = "/dev/disk/by-label/nixos"; fsType = "ext4"; @@ -24,11 +25,7 @@ with lib; networking.useNetworkd = mkForce true; networking.networkmanager.enable = false; - #networking.interfaces.ens18.useDHCP = false; - #networking.bridges.br0.interfaces = [ "ens18" ]; - #networking.interfaces.br0.useDHCP = lib.mkDefault true; - # hardware.cpu.amd.updateMicrocode = lib.config.hardware.enableRedistributableFirmware; boot.initrd.availableKernelModules = [ "virtio_net" "virtio_pci" "virtio_mmio" "virtio_blk" "virtio_scsi" "9p" "9pnet_virtio" ]; boot.initrd.kernelModules = [ "virtio_balloon" "virtio_console" "virtio_rng" ]; @@ -46,6 +43,5 @@ with lib; services.qemuGuest.enable = true; - cascade.bridge-interface = "ens18"; }; } diff --git a/shell.nix b/shell.nix old mode 100755 new mode 100644 index f1c02c8..838393e --- a/shell.nix +++ b/shell.nix @@ -13,20 +13,16 @@ stdenv.mkDerivation { buildInputs = [ terraform vault coreutils-full dig bash samba4Full morph ]; shellHook = '' - export NIX_PATH="nixpkgs=${toString }" + export NIX_PATH="nixpkgs=${toString }:morph-options=${morph.lib}/options.nix" export LD_LIBRARY_PATH="${libvirt}/lib:$LD_LIBRARY_PATH" export VAULT_ADDR=${escapeShellArg vault_addr} export DOMAIN="$(hostname -d)" - +PROXMOX_STORAGE=hdd-fs MEMORY=2048 -name="$1" rebuild-nixos-image() { - echo "$(nix-build \ - -I nixos-config=custom-image-configuration.nix \ - -I hardware-config=profiles/qemu-vm/default.nix \ - custom-image.nix)/nixos".img + echo "$(nix-build custom-image.nix)/nixos".img } mkvirt() { @@ -56,7 +52,7 @@ mkvirt() { --net0 virtio,bridge=vmbr0 \ --ipconfig0 ip=dhcp \ --agent enabled=1,type=virtio \ - --virtio0 hdd-fs:0,import-from="$IMG",discard=on,format=raw \ + --virtio0 "$PROXMOX_STORAGE":0,import-from="$IMG",discard=on,format=raw \ --boot c \ --bootdisk virtio0 \ --vga serial0 \ @@ -187,10 +183,11 @@ deploy() { } destroy-host() { + eval "$(env_cascade)" while [ $# -gt 0 ];do - - VMID="$(sudo qm list | awk -v N="$1" '$2 == N {print $1}')" + eval "$(env_name "$1")" + VMID="$(sudo qm list | awk -v N="$1" '$2 == N {print $name}')" echo "destroying hosts/$1.nix and VM #$VMID" 1>&2 sleep 1 @@ -199,6 +196,8 @@ destroy-host() { sudo qm destroy $VMID rm -f hosts/"$1".nix + samba-tool dns cleanup -k yes "$DC" "$name"."$DOMAIN" + shift done }