Skip to content

Instantly share code, notes, and snippets.

@rickynils
Created March 22, 2014 19:36
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rickynils/9713047 to your computer and use it in GitHub Desktop.
Save rickynils/9713047 to your computer and use it in GitHub Desktop.
NixOS libvirt/qemu
network:
with (import <nixpkgs> {});
with lib;
with builtins;
let
hosts = attrNames network;
sys = name: let cfg = getAttr name network; in import <nixpkgs/nixos> {
configuration = attrs: (cfg attrs) // {
networking.hostName = name;
};
};
system = name: (sys name).system;
config = name: (sys name).config;
# Only used to create a unique source for MAC generation that is guaranteed
# to change if anything in the network changes.
allSystems = runCommand "qemu-network-systems" {} ''
mkdir -p $out
${concatMapStrings (s: "ln -s ${s} $out/;") (map system hosts)}
'';
mkNetdev = n: attrs: ''
<qemu:arg value='-netdev'/>
<qemu:arg value='vde,sock=${attrs.vdeSocket},id=${n}'/>
<qemu:arg value='-device'/>
<qemu:arg value='virtio-net-pci,netdev=${n},mac=${attrs.mac}'/>
'';
mkNetdevQemu = n: attrs: ''
-netdev \
vde,sock=${attrs.vdeSocket},id=${n} \
-device \
virtio-net-pci,netdev=${n},mac=${attrs.mac} \
'';
libvirtxml = name: let
sys = system name;
cfg = (config name).deployment.libvirt;
in runCommand "libvirtxml" {} ''
MAC0=$(echo "${name}${allSystems}0" | md5sum | \
sed 's/^\(..\)\(..\)\(..\)\(..\)\(..\).*$/02:\1:\2:\3:\4:\5/')
MAC1=$(echo "${name}${allSystems}1" | md5sum | \
sed 's/^\(..\)\(..\)\(..\)\(..\)\(..\).*$/02:\1:\2:\3:\4:\5/')
MAC2=$(echo "${name}${allSystems}2" | md5sum | \
sed 's/^\(..\)\(..\)\(..\)\(..\)\(..\).*$/02:\1:\2:\3:\4:\5/')
MAC3=$(echo "${name}${allSystems}3" | md5sum | \
sed 's/^\(..\)\(..\)\(..\)\(..\)\(..\).*$/02:\1:\2:\3:\4:\5/')
MAC4=$(echo "${name}${allSystems}4" | md5sum | \
sed 's/^\(..\)\(..\)\(..\)\(..\)\(..\).*$/02:\1:\2:\3:\4:\5/')
UUID=$(echo "${name}${allSystems}" | md5sum | \
sed 's/^\(........\)\(....\)\(....\)\(....\)\(............\).*$/\1-\2-\3-\4-\5/')
mkdir $out
cat << EOF > $out/qemu-cmd
${qemu}/bin/qemu-system-x86_64 \
-m ${toString cfg.memory} \
-kernel ${sys}/kernel \
-initrd ${sys}/initrd \
-append "$(cat ${sys}/kernel-params) init=${sys}/init" \
-fsdev \
local,id=nixstore,path=/nix/store,security_model=none,readonly \
-device \
virtio-9p-pci,fsdev=nixstore,mount_tag=nixstore \
-fsdev \
local,id=nixvar,path=/nix/var,security_model=none,readonly \
-device \
virtio-9p-pci,fsdev=nixvar,mount_tag=nixvar \
${concatStrings (mapAttrsToList mkNetdevQemu cfg.netdevs)}
EOF
chmod +x $out/qemu-cmd
cat << EOF > $out/libvirt.xml
<domain type='kvm' xmlns:qemu='http://libvirt.org/schemas/domain/qemu/1.0'>
<name>${name}</name>
<uuid>${cfg.uuid}</uuid>
<memory unit='M'>${toString cfg.memory}</memory>
<currentMemory unit='M'>${toString cfg.memory}</currentMemory>
<vcpu placement='static'>2</vcpu>
<os>
<type>hvm</type>
<kernel>${sys}/kernel</kernel>
<initrd>${sys}/initrd</initrd>
<cmdline>$(cat ${sys}/kernel-params) console=ttyS0 init=${sys}/init</cmdline>
</os>
<features><acpi/></features>
<cpu><model>kvm64</model></cpu>
<clock offset='utc'/>
<on_poweroff>destroy</on_poweroff>
<on_reboot>restart</on_reboot>
<on_crash>destroy</on_crash>
<devices>
<emulator>${qemu}/bin/qemu-system-x86_64</emulator>
<memballoon model='virtio'/>
<serial type='pty'><target port='0'/></serial>
<console type='pty'><target type='serial' port='0'/></console>
</devices>
<qemu:commandline>
<qemu:arg value='-fsdev'/>
<qemu:arg value='local,id=nixstore,path=/nix/store,security_model=none,readonly'/>
<qemu:arg value='-device'/>
<qemu:arg value='virtio-9p-pci,fsdev=nixstore,mount_tag=nixstore'/>
<qemu:arg value='-fsdev'/>
<qemu:arg value='local,id=nixvar,path=/nix/var,security_model=none,readonly'/>
<qemu:arg value='-device'/>
<qemu:arg value='virtio-9p-pci,fsdev=nixvar,mount_tag=nixvar'/>
${concatStrings (mapAttrsToList mkNetdev cfg.netdevs)}
</qemu:commandline>
</domain>
EOF
'';
in runCommand "qemu-network" {} ''
mkdir -p $out
${concatStrings (map (n: "ln -sfT ${libvirtxml n}/libvirt.xml $out/${n}.xml;") hosts)}
${concatStrings (map (n: "ln -sfT ${libvirtxml n}/qemu-cmd $out/${n}.cmd;") hosts)}
''
{ config, pkgs, ... }:
with pkgs.lib;
{
options = {
deployment.libvirt.memory = mkOption {
default = 128;
type = types.int;
description = "The amount of memory in MB";
};
deployment.libvirt.mountHostStore = mkOption {
default = true;
type = types.bool;
description = "Wether to mount /nix/store from the host";
};
deployment.libvirt.uuid = mkOption {
default = "$UUID";
type = types.string;
description = ''
The UUID of the machine. Set it to $UUID to automatically
generate a UUID
'';
};
deployment.libvirt.netdevs = mkOption {
default = {};
type = types.attrsOf types.optionSet;
description = "netdevs";
options = {
vdeSocket = mkOption {
type = types.string;
description = "The path to the VDE ctl socket directory";
};
mac = mkOption {
type = types.string;
description = ''
The MAC address of the device. You can use the special values
$MAC0, $MAC1, $MAC2 etc to get generated MAC addresses.
'';
};
};
};
};
config = {
boot = {
kernelParams = [ "logo.nologo" ];
initrd.kernelModules = [ "9p" "virtio_pci" "9pnet_virtio" ];
kernelModules = [ "virtio_net" ];
loader.grub.enable = false;
vesa = false;
postBootCommands = ''
touch /etc/NIXOS
'';
};
fileSystems = {
"/" = {
fsType = "tmpfs";
device = "tmpfs";
options = "mode=0755";
};
} // (if !config.deployment.libvirt.mountHostStore then {} else {
"/nix/store" = mkIf (config.deployment.libvirt.mountHostStore) {
fsType = "9p";
device = "nixstore";
neededForBoot = true;
options = "trans=virtio,version=9p2000.L,ro";
};
});
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment