commit ad2092531cdfedd9462dd2f5e3ab281e0d502878 Author: Sagar Ch Date: Thu May 23 16:33:38 2024 +0000 fist commit - images lib in a working condition for debian diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b2be92b --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +result diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..5ab4db7 --- /dev/null +++ b/flake.lock @@ -0,0 +1,27 @@ +{ + "nodes": { + "nixpkgs": { + "locked": { + "lastModified": 1715534503, + "narHash": "sha256-5ZSVkFadZbFP1THataCaSf0JH2cAH3S29hU9rrxTEqk=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "2057814051972fa1453ddfb0d98badbea9b83c06", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "nixpkgs": "nixpkgs" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..60f3421 --- /dev/null +++ b/flake.nix @@ -0,0 +1,27 @@ +{ + description = "builds a qemu image and qemu command scripts to run with systemd services"; + + inputs = { + nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable"; + }; + + outputs = { self, nixpkgs, ... }: + let + system = "x86_64-linux"; + pkgs = nixpkgs.legacyPackages.${system}; + lib = pkgs.lib; + vmixLib = (import ./lib { inherit pkgs lib system; }); + in { + packages."${system}" = with vmixLib; rec { + playfuldeb = customizeImage images.debian.v12.play { + name = "playfulness"; + }; + + nixmox = customizeImage images.debian.v12.proxmox (images.debian.customs.rooted // { + name = "nixmox"; + }); + + default = playfuldeb; + }; + }; +} \ No newline at end of file diff --git a/lib/default.nix b/lib/default.nix new file mode 100644 index 0000000..4efda56 --- /dev/null +++ b/lib/default.nix @@ -0,0 +1,8 @@ +{ pkgs, lib, system ? "x86_64-linux", ... }: +let + images = import ./images { inherit pkgs lib system; }; +in +{ + inherit images; + inherit (images.commons) customizeImage; +} \ No newline at end of file diff --git a/lib/images/commons/customizeImage.nix b/lib/images/commons/customizeImage.nix new file mode 100644 index 0000000..f6b2f41 --- /dev/null +++ b/lib/images/commons/customizeImage.nix @@ -0,0 +1,49 @@ +# wrapper function around virt-customize to create custom OS image from an original OS image +{ pkgs, lib, ... }: + originalImage: { + name, + hostname ? "", + nameToHostname ? true, + diskSize ? "", + smp ? 2, + memSize ? 1024, + install ? [], + run ? "", + commands ? "", + osType ? "linux" + }: + let + originalImageName = lib.strings.removeSuffix "-vmix" (lib.strings.removeSuffix ".qcow2" originalImage.name); + resultImg = "./disk.qcow2"; + qemuWrapperScript = (pkgs.writeShellScript "qemu-wrapper-script" '' + export PATH="${pkgs.qemu}/bin:$PATH" + exec qemu-kvm -nic user,model=virtio-net-pci "$@" + ''); + setHostname = if hostname != "" then hostname else if nameToHostname then name else ""; + virtCustomizeArgsHostname = if setHostname != "" then "--hostname '${setHostname}'" else ""; + virtCustomizeArgsInstall = if install != [] then "--install '${lib.strings.concatStringsSep "," install }'" else ""; + virtCustomizeArgsCommandsFile = if commands != "" then ("--commands-from-file " + pkgs.writeText "${name}-vmix-virt-customize-commands-file" commands) else ""; + virtCustomizeArgsRun = if run != "" then ("--run " + pkgs.writeScript "${name}-vmix-virt-customize-run-script" "${run}") else ""; + in + pkgs.runCommand "${name}-${originalImageName}-vmix.qcow2" { __noChroot = true; } '' + export PATH="${pkgs.qemu}/bin:${pkgs.curl}/bin:$PATH" + + # create resulting image backed by original image + qemu-img create -f qcow2 -b ${originalImage} -F qcow2 ${resultImg} + [ -n "${diskSize}" ] && qemu-img resize ${resultImg} ${diskSize} + + # run script inside image using virt-customize + export LIBGUESTFS_APPEND="ipv6.disable=1" + #export LIBGUESTFS_HV="${qemuWrapperScript}" + + ${pkgs.guestfs-tools}/bin/virt-customize \ + -a ${resultImg} \ + --smp ${builtins.toString smp} \ + --memsize ${builtins.toString memSize} \ + ${virtCustomizeArgsHostname} \ + ${virtCustomizeArgsInstall} \ + ${virtCustomizeArgsCommandsFile} \ + ${virtCustomizeArgsRun} + + mv ${resultImg} $out + '' \ No newline at end of file diff --git a/lib/images/commons/default.nix b/lib/images/commons/default.nix new file mode 100644 index 0000000..6e0f176 --- /dev/null +++ b/lib/images/commons/default.nix @@ -0,0 +1,5 @@ +{ pkgs, lib, ... }: { + # basic scripts and files used across various OS images + customizeImage = (import ./customizeImage.nix) { inherit pkgs lib; }; + scriptsNFiles = (import ./scripts-n-files.nix) { inherit pkgs lib; }; +} \ No newline at end of file diff --git a/lib/images/commons/scripts-n-files.nix b/lib/images/commons/scripts-n-files.nix new file mode 100644 index 0000000..6540f71 --- /dev/null +++ b/lib/images/commons/scripts-n-files.nix @@ -0,0 +1,59 @@ +# minimal set of scripts and services by various images +{ pkgs, lib, ... }: { + # bring back simple interface names like eth0 eth1 etc + grub-ifnames-0 = pkgs.writeText "grub-ifnames-0" '' + GRUB_CMDLINE_LINUX="net.ifnames=0 biosdevname=0 $GRUB_CMDLINE_LINUX" + ''; + + # no need for CPU microcode updating in VMs + grub-disable-microcode = pkgs.writeText "grub-disable-microcode" '' + GRUB_CMDLINE_LINUX="dis_ucode_ldr $GRUB_CMDLINE_LINUX" + ''; + + # dhcp for eth0 + eth0-dhcp-network = pkgs.writeText "eth0-network" '' + [Match] + Name=eth0 + + [Network] + DHCP=yes + ''; + + # generate ssh host keys before starting sshd + ssh-service-override-conf-create = pkgs.writeScript "ssh-override-conf-create.sh" '' + mkdir -p /etc/systemd/system/ssh.service.d + + cat > /etc/systemd/system/ssh.service.d/override.conf << EOF + [Service] + ExecStartPre= + ExecStartPre=`which ssh-keygen` -A + ExecStartPre=`which sshd` -t + + EOF + ''; + + # script to grow root partition + grow-root-sh = pkgs.writeScript "grow-root-sh" '' + #!/bin/bash + set -e + + command -v growpart >/dev/null || { >&2 echo "growpart not found. Install package cloud-guest-utils or cloud-utils."; exit 1; } + + ROOTPART=$(findmnt / -o source -n) + DISK=''${ROOTPART%[0-9]*} + PARTNUM=''${ROOTPART##*[!0-9]} + + # resize and grow if possible + growpart "$DISK" "$PARTNUM" && resize2fs "$ROOTPART" || true + ''; + + # service to grow root partition on boot + grow-root-service = pkgs.writeText "grow-root-service" '' + [Service] + Type = oneshot + ExecStart = /usr/local/sbin/grow-root.sh + + [Install] + WantedBy = multi-user.target + ''; +} \ No newline at end of file diff --git a/lib/images/debian/customs.nix b/lib/images/debian/customs.nix new file mode 100644 index 0000000..5796692 --- /dev/null +++ b/lib/images/debian/customs.nix @@ -0,0 +1,63 @@ +# ready to use customizations to apply on images +{ pkgs, lib, system, commons, ... }: +with commons; +with scriptsNFiles; +{ + # essential functionalities like ssh, networking etc + essentials = { + install = [ "htop" "openssh-server" "inetutils-ping" "dnsutils" "cloud-guest-utils" "qemu-guest-agent" ]; + commands = '' + upload ${grub-ifnames-0}:/etc/default/grub.d/90-ifnames-0.cfg + upload ${grub-disable-microcode}:/etc/default/grub.d/00-disable-microcode.cfg + run-command mount /boot/efi && update-grub + upload ${eth0-dhcp-network}:/etc/systemd/network/00-eth0-dhcp.network + run ${ssh-service-override-conf-create} + upload ${grow-root-sh}:/usr/local/sbin/grow-root.sh + upload ${grow-root-service}:/etc/systemd/system/grow-root.service + run-command systemctl enable grow-root.service + ''; + }; + + # set easy root access + rooted = { + run = '' + # set root password and ssh access + echo "root:root" | chpasswd + sed -i '/PasswordAuthentication no/d' "/etc/ssh/sshd_config" + echo "PasswordAuthentication yes\nPermitRootLogin yes" >> "/etc/ssh/sshd_config" + ''; + }; + + # install proxmox + proxmoxOnDebian12 = { + diskSize = "+2G"; + smp = 4; + memSize = 4096; + run = '' + # script originally taken from https://pve.proxmox.com/wiki/Install_Proxmox_VE_on_Debian_12_Bookworm + # exit if error + set -e + + # grow root partition - script installed in "base" image + /usr/local/sbin/grow-root.sh + + # mount efi for grub changes + mount /boot/efi + + # add proxmox repo + echo "deb [arch=amd64] http://download.proxmox.com/debian/pve bookworm pve-no-subscription" > /etc/apt/sources.list.d/pve-install-repo.list + wget https://enterprise.proxmox.com/debian/proxmox-release-bookworm.gpg -O /etc/apt/trusted.gpg.d/proxmox-release-bookworm.gpg + apt-get update && apt full-upgrade -y --no-install-recommends; + + # necessary precursors + echo "0.0.0.0\t\t`cat /etc/hostname`" >> /etc/hosts; # necessary for SSL certificate creation + mkdir -p /run/network; # bug https://github.com/CumulusNetworks/ifupdown2/issues/276 + + # install + apt install -y proxmox-default-kernel proxmox-ve postfix open-iscsi chrony --no-install-recommends; + + # remove previous kernels + apt remove -y os-prober linux-image-amd64 'linux-image-6.*'; + ''; + }; +} diff --git a/lib/images/debian/default.nix b/lib/images/debian/default.nix new file mode 100644 index 0000000..fa511b1 --- /dev/null +++ b/lib/images/debian/default.nix @@ -0,0 +1,16 @@ +{ pkgs, lib, system, commons, ... }: +let + # upstream distro images + upstreamImagesJSON = lib.importJSON ./upstream.json; + upstreamImages = lib.mapAttrs (name: src: pkgs.fetchurl src) upstreamImagesJSON.${system}; + customs = (import ./customs.nix) { inherit pkgs lib system commons; }; + templates = (import ./templates.nix) { inherit pkgs lib system commons upstreamImages customs; }; + mergeUpstreamImageAndTemplates = + name: image: + let + imageTemplates = lib.optionalAttrs (lib.hasAttr "${name}" templates) templates.${name}; + in + imageTemplates // { upstream = image; }; + + images = lib.mapAttrs mergeUpstreamImageAndTemplates upstreamImages; +in images // { inherit customs; } \ No newline at end of file diff --git a/lib/images/debian/templates.nix b/lib/images/debian/templates.nix new file mode 100644 index 0000000..a9db3da --- /dev/null +++ b/lib/images/debian/templates.nix @@ -0,0 +1,24 @@ +# create additional useful template images from upstream images +{ pkgs, lib, system, commons, upstreamImages, customs, ... }: +with commons; +with scriptsNFiles; +{ + v12 = rec { + # default image with essential functionalities like ssh, networking etc + default = customizeImage upstreamImages.v12 (customs.essentials // { + name = "default"; + hostname = "debian"; + }); + + # playground with easy root access + play = customizeImage default (customs.rooted // { + name = "play"; + nameToHostname = false; + }); + + # proxmox + proxmox = customizeImage default (customs.proxmoxOnDebian12 // { + name = "proxmox"; + }); + }; +} \ No newline at end of file diff --git a/lib/images/debian/upstream.json b/lib/images/debian/upstream.json new file mode 100644 index 0000000..fda8398 --- /dev/null +++ b/lib/images/debian/upstream.json @@ -0,0 +1,22 @@ +{ + "aarch64-linux": { + "v12": { + "sha256": "00gzq6pvpw2idvb4nl4chw6x7j9qjqj7d1j4hsngm241bks6b8h1", + "url": "https://cloud.debian.org/images/cloud/bookworm/20240507-1740/debian-12-generic-arm64-20240507-1740.qcow2" + }, + "v13": { + "sha256": "01liz34ikbqp7ij9ajginizxcrk1fiw3flqchq01knl8mar3givk", + "url": "https://cloud.debian.org/images/cloud/trixie/daily/20240512-1745/debian-13-generic-arm64-daily-20240512-1745.qcow2" + } + }, + "x86_64-linux": { + "v12": { + "sha256": "0inga3c772wr9b296w86n8prlqvw47wd6b5z8347pygiw810y5yq", + "url": "https://cloud.debian.org/images/cloud/bookworm/20240507-1740/debian-12-generic-amd64-20240507-1740.qcow2" + }, + "v13": { + "sha256": "1bixl6gnzigwryac1arc3n81nv4hwdi6wxpwmvrgigzni64b3x6w", + "url": "https://cloud.debian.org/images/cloud/trixie/daily/20240512-1745/debian-13-generic-amd64-daily-20240512-1745.qcow2" + } + } +} \ No newline at end of file diff --git a/lib/images/default.nix b/lib/images/default.nix new file mode 100644 index 0000000..1d4cbbc --- /dev/null +++ b/lib/images/default.nix @@ -0,0 +1,7 @@ +{ pkgs, lib, system, ... }: +let + commons = (import ./commons) { inherit pkgs lib system; }; + debian = (import ./debian) { inherit pkgs lib system commons; }; +in { + inherit commons debian; +} \ No newline at end of file