Skip to content

Commit 3b39c12

Browse files
Merge pull request #336 from Ramblurr/feat/expose-cloud-hypervisor-platform-opts
cloud-hypervisor: add platformOEMStrings and `--platform` merging
2 parents 5e193f2 + 7d8bb71 commit 3b39c12

File tree

5 files changed

+93
-5
lines changed

5 files changed

+93
-5
lines changed

lib/default.nix

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,4 +78,59 @@ rec {
7878
import ./macvtap.nix {
7979
inherit microvmConfig hypervisorConfig lib;
8080
};
81+
82+
/*
83+
extractOptValues - Extract and remove all occurrences of a command-line option and its values from a list of arguments.
84+
85+
Description:
86+
This function searches for a specified option flag in a list of command-line arguments,
87+
extracts ALL associated values, and returns both the values and a filtered list with
88+
all occurrences of the option flag and its values removed. The order of all other
89+
arguments is preserved. Uses tail recursion to process the argument list.
90+
91+
Parameters:
92+
optFlag :: String | [String] - The option flag(s) to search for. Can be:
93+
- A single string (e.g., "-platform")
94+
- A list of strings (e.g., ["-p" "-platform"])
95+
All matching flags and their values are extracted
96+
extraArgs :: [String] - A list of command-line arguments
97+
98+
Returns:
99+
{
100+
values :: [String] - List of all values associated with matching flags (empty list if none found)
101+
args :: [String] - The input list with all matched flags and their values removed
102+
}
103+
104+
Examples:
105+
# Extract single occurrence:
106+
extractOptValues "-platform" ["-vnc" ":0" "-platform" "linux" "-usb"]
107+
=> { values = ["linux"]; args = ["-vnc" ":0" "-usb"]; }
108+
109+
# Extract multiple occurrences:
110+
extractOptValues "-b" ["-a" "a" "-b" "b" "-c" "c" "-b" "b2"]
111+
=> { values = ["b" "b2"]; args = ["-a" "a" "-c" "c"]; }
112+
113+
# Extract with multiple flag aliases:
114+
extractOptValues ["-p" "-platform"] ["-p" "short" "-vnc" ":0" "-platform" "long" "-usb"]
115+
=> { values = ["short" "long"]; args = ["-vnc" ":0" "-usb"]; }
116+
117+
# Degenerate case with no matches:
118+
extractOptValues ["-p" "-platform"] ["-vnc" ":0" "-usb"]
119+
=> { values = []; args = ["-vnc" ":0" "-usb"]; }
120+
*/
121+
extractOptValues = optFlag: extraArgs:
122+
let
123+
flags = if builtins.isList optFlag then optFlag else [optFlag];
124+
125+
processArgs = args: values: acc:
126+
if args == [] then
127+
{ values = values; args = acc; }
128+
else if (builtins.elem (builtins.head args) flags) && (builtins.length args) > 1 then
129+
# Found one of the option flags, skip it and its value
130+
processArgs (builtins.tail (builtins.tail args)) (values ++ [(builtins.elemAt args 1)]) acc
131+
else
132+
# Not the option we're looking for, keep this element
133+
processArgs (builtins.tail args) values (acc ++ [(builtins.head args)]);
134+
in
135+
processArgs extraArgs [] [];
81136
}

lib/runner.nix

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,13 @@ let
88

99
inherit (microvmConfig) hostName;
1010

11-
inherit (import ./. { inherit lib; }) createVolumesScript makeMacvtap withDriveLetters;
11+
inherit (import ./. { inherit lib; }) createVolumesScript makeMacvtap withDriveLetters extractOptValues;
1212
inherit (makeMacvtap {
1313
inherit microvmConfig hypervisorConfig;
1414
}) openMacvtapFds macvtapFds;
1515

1616
hypervisorConfig = import (./runners + "/${microvmConfig.hypervisor}.nix") {
17-
inherit pkgs microvmConfig macvtapFds withDriveLetters;
17+
inherit pkgs microvmConfig macvtapFds withDriveLetters extractOptValues;
1818
};
1919

2020
inherit (hypervisorConfig) command canShutdown shutdownCommand;

lib/runners/cloud-hypervisor.nix

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
{ pkgs
22
, microvmConfig
33
, macvtapFds
4+
, extractOptValues
45
, ...
56
}:
67

78
let
89
inherit (pkgs) lib;
910
inherit (microvmConfig) vcpu mem balloon initialBalloonMem deflateOnOOM hotplugMem hotpluggedMem user interfaces volumes shares socket devices hugepageMem graphics storeDisk storeOnDisk kernel initrdPath;
10-
inherit (microvmConfig.cloud-hypervisor) extraArgs;
11+
inherit (microvmConfig.cloud-hypervisor) platformOEMStrings extraArgs;
1112

1213
kernelPath = {
1314
x86_64-linux = "${kernel.dev}/vmlinux";
@@ -94,6 +95,12 @@ let
9495

9596
supportsNotifySocket = true;
9697

98+
oemStringValues = platformOEMStrings ++ lib.optional supportsNotifySocket "io.systemd.credential:vmm.notify_socket=vsock-stream:2:8888";
99+
oemStringOptions = lib.optional (oemStringValues != []) "oem_strings=[${lib.concatStringsSep "," oemStringValues}]";
100+
platformExtracted = extractOptValues "--platform" extraArgs;
101+
extraArgsWithoutPlatform = platformExtracted.args;
102+
userPlatformOpts = platformExtracted.values;
103+
platformOps = lib.concatStringsSep "," (oemStringOptions ++ userPlatformOpts);
97104
in {
98105
inherit tapMultiQueue;
99106

@@ -147,10 +154,10 @@ in {
147154
"--cmdline" "${kernelConsole} reboot=t panic=-1 ${builtins.unsafeDiscardStringContext (toString microvmConfig.kernelParams)}"
148155
"--seccomp" "true"
149156
"--memory" memOps
157+
"--platform" platformOps
150158
]
151159
++
152160
lib.optionals supportsNotifySocket [
153-
"--platform" "oem_strings=[io.systemd.credential:vmm.notify_socket=vsock-stream:2:8888]"
154161
"--vsock" "cid=3,socket=notify.vsock"
155162
]
156163
++
@@ -223,7 +230,7 @@ in {
223230
usb = throw "USB passthrough is not supported on cloud-hypervisor";
224231
}.${bus}) devices
225232
)
226-
) + " " + lib.escapeShellArgs extraArgs;
233+
) + " " + lib.escapeShellArgs extraArgsWithoutPlatform;
227234

228235
canShutdown = socket != null;
229236

nixos-modules/microvm/asserts.nix

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,8 +105,17 @@ lib.mkIf config.microvm.guest.enable {
105105
message = ''
106106
MicroVM ${hostName}: `config.microvm.forwardPorts` works only with qemu and one network interface with `type = "user"`
107107
'';
108+
} ]
109+
++
110+
# cloud-hypervisor specific asserts
111+
lib.optionals (config.microvm.hypervisor == "cloud-hypervisor") [ {
112+
assertion = ! (lib.any (str: lib.hasInfix "oem_strings" str) config.microvm.cloud-hypervisor.platformOEMStrings);
113+
message = ''
114+
MicroVM ${hostName}: `config.microvm.cloud-hypervisor.platformOEMStrings` items must not contain `oem_strings`
115+
'';
108116
} ];
109117

118+
110119
warnings =
111120
# 32 MB is just an optimistic guess, not based on experience
112121
lib.optional (config.microvm.mem < 32) ''

nixos-modules/microvm/options.nix

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -515,6 +515,23 @@ in
515515
'';
516516
};
517517

518+
cloud-hypervisor.platformOEMStrings = mkOption {
519+
type = with types; listOf str;
520+
default = [];
521+
description = ''
522+
Extra arguments to pass to cloud-hypervisor's --platform oem_strings=[] argument.
523+
524+
All the oem strings will be concatenated with a comma (,) and wrapped in oem_string=[].
525+
526+
Do not include oem_string= or the [] brackets in the value.
527+
528+
The resulting string will be combined with any --platform options in
529+
`config.microvm.cloud-hypervisor.extraArgs` and passed as a single
530+
--platform option to cloud-hypervisor
531+
'';
532+
example = lib.literalExpression /* nix */ ''[ "io.systemd.credential:APIKEY=supersecret" ]'';
533+
};
534+
518535
cloud-hypervisor.extraArgs = mkOption {
519536
type = with types; listOf str;
520537
default = [];

0 commit comments

Comments
 (0)