dotfiles/example/microvm/asserts.nix
2025-11-07 13:36:30 -06:00

128 lines
4.3 KiB
Nix
Executable file

{ config, lib, ... }:
let
inherit (config.networking) hostName;
in
lib.mkIf config.microvm.guest.enable {
assertions =
# check for duplicate volume images
map (volumes: {
assertion = builtins.length volumes == 1;
message = ''
MicroVM ${hostName}: volume image "${(builtins.head volumes).image}" is used ${toString (builtins.length volumes)} > 1 times.
'';
}) (builtins.attrValues (builtins.groupBy ({ image, ... }: image) config.microvm.volumes))
++
# check for duplicate interface ids
map (interfaces: {
assertion = builtins.length interfaces == 1;
message = ''
MicroVM ${hostName}: interface id "${(builtins.head interfaces).id}" is used ${toString (builtins.length interfaces)} > 1 times.
'';
}) (builtins.attrValues (builtins.groupBy ({ id, ... }: id) config.microvm.interfaces))
++
# check for bridge interfaces
map (
{
id,
type,
bridge,
...
}:
if type == "bridge" then
{
assertion = bridge != null;
message = ''
MicroVM ${hostName}: interface ${id} is of type "bridge"
but doesn't have a bridge to attach to defined.
'';
}
else
{
assertion = bridge == null;
message = ''
MicroVM ${hostName}: interface ${id} is not of type "bridge"
and therefore shouldn't have a "bridge" option defined.
'';
}
) config.microvm.interfaces
++
# check for interface name length
map (
{ id, ... }:
{
assertion = builtins.stringLength id <= 15;
message = ''
MicroVM ${hostName}: interface name ${id} is longer than the
the maximum length of 15 characters on Linux.
'';
}
) config.microvm.interfaces
++
# check for duplicate share tags
map (shares: {
assertion = builtins.length shares == 1;
message = ''
MicroVM ${hostName}: share tag "${(builtins.head shares).tag}" is used ${toString (builtins.length shares)} > 1 times.
'';
}) (builtins.attrValues (builtins.groupBy ({ tag, ... }: tag) config.microvm.shares))
++
# check for duplicate share sockets
map
(shares: {
assertion = builtins.length shares == 1;
message = ''
MicroVM ${hostName}: share socket "${(builtins.head shares).socket}" is used ${toString (builtins.length shares)} > 1 times.
'';
})
(
builtins.attrValues (
builtins.groupBy ({ socket, ... }: toString socket) (
builtins.filter ({ proto, ... }: proto == "virtiofs") config.microvm.shares
)
)
)
++
# check for virtiofs shares without socket
map (
{ tag, socket, ... }:
{
assertion = socket != null;
message = ''
MicroVM ${hostName}: virtiofs share with tag "${tag}" is missing a `socket` path.
'';
}
) (builtins.filter ({ proto, ... }: proto == "virtiofs") config.microvm.shares)
++
# blacklist forwardPorts
[
{
assertion =
config.microvm.forwardPorts != [ ]
-> (
config.microvm.hypervisor == "qemu"
&& builtins.any ({ type, ... }: type == "user") config.microvm.interfaces
);
message = ''
MicroVM ${hostName}: `config.microvm.forwardPorts` works only with qemu and one network interface with `type = "user"`
'';
}
]
++
# cloud-hypervisor specific asserts
lib.optionals (config.microvm.hypervisor == "cloud-hypervisor") [
{
assertion =
!(lib.any (str: lib.hasInfix "oem_strings" str) config.microvm.cloud-hypervisor.platformOEMStrings);
message = ''
MicroVM ${hostName}: `config.microvm.cloud-hypervisor.platformOEMStrings` items must not contain `oem_strings`
'';
}
];
warnings =
# 32 MB is just an optimistic guess, not based on experience
lib.optional (config.microvm.mem < 32) ''
MicroVM ${hostName}: ${toString config.microvm.mem} MB of RAM is uncomfortably narrow.
'';
}