nix-required-mounts: init

This commit is contained in:
Someone Serge 2023-09-19 12:28:30 +03:00
parent 2bfe2058a3
commit b422dafc89
5 changed files with 263 additions and 0 deletions

View File

@ -243,6 +243,7 @@
./programs/nh.nix
./programs/nix-index.nix
./programs/nix-ld.nix
./programs/nix-required-mounts.nix
./programs/nm-applet.nix
./programs/nncp.nix
./programs/noisetorch.nix

View File

@ -0,0 +1,85 @@
{ config, lib, pkgs, ... }:
let
cfg = config.programs.nix-required-mounts;
hook =
pkgs.nix-required-mounts.override { inherit (cfg) allowedPatterns; };
patternType = with lib.types; submodule ({ config, name, ... }: {
options.onFeatures = lib.mkOption {
type = listOf str;
description = "Which requiredSystemFeatures should trigger relaxation of the sandbox";
default = [ name ];
};
options.paths = lib.mkOption {
type = listOf path;
description = "A list of glob patterns, indicating which paths to expose to the sandbox";
};
});
defaults = {
opengl.onFeatures = [ "opengl" ];
opengl.paths = [
"/dev/video*"
"/dev/dri"
pkgs.addOpenGLRunpath.driverLink
# /run/opengl-driver/lib only contains symlinks
config.hardware.opengl.package
] ++ config.hardware.opengl.extraPackages;
cuda.onFeatures = [ "cuda" ];
cuda.paths = defaults.opengl.paths ++ [ "/dev/nvidia*" ];
};
in
{
meta.maintainers = with lib.maintainers; [ SomeoneSerge ];
options.programs.nix-required-mounts = {
enable = lib.mkEnableOption
"Expose extra paths to the sandbox depending on derivations' requiredSystemFeatures";
presets.opengl.enable = lib.mkOption {
type = lib.types.bool;
default = config.hardware.opengl.enable;
defaultText = lib.literalExpression "hardware.opengl.enable";
description = ''
Expose OpenGL drivers to derivations marked with requiredSystemFeatures = [ "opengl" ]
'';
};
presets.cuda.enable = lib.mkEnableOption ''
Expose CUDA drivers and GPUs to derivations marked with requiredSystemFeatures = [ "cuda" ]
'';
allowedPatterns = with lib.types;
lib.mkOption rec {
type = attrsOf patternType;
description = "The hook config, describing which paths to mount for which system features";
default = { inherit (defaults) opengl; };
defaultText = lib.literalExpression ''
{
opengl.paths = config.hardware.opengl.extraPackages ++ [
config.hardware.opengl.package
pkgs.addOpenGLRunpath.driverLink
"/dev/video*"
"/dev/dri"
];
}
'';
example.require-ipfs = [ "/ipfs" ];
};
};
config = lib.mkIf cfg.enable (lib.mkMerge [
{
nix.settings.pre-build-hook = lib.getExe hook;
}
(lib.mkIf cfg.presets.opengl.enable {
nix.settings.system-features = [ "opengl" ];
programs.nix-required-mounts.allowedPatterns = {
inherit (defaults) opengl;
};
})
(lib.mkIf cfg.presets.cuda.enable {
nix.settings.system-features = [ "cuda" ];
programs.nix-required-mounts.allowedPatterns = {
inherit (defaults) cuda;
};
})
]);
}

View File

@ -0,0 +1,118 @@
import glob
import json
import subprocess
import textwrap
from argparse import ArgumentParser
from itertools import chain
from pathlib import Path
from sys import stderr
from typing import List
CONFIG = {
"nixExe": "nix",
"allowedPatterns": {},
}
parser = ArgumentParser("pre-build-hook")
parser.add_argument("derivation_path")
parser.add_argument("sandbox_path", nargs="?")
parser.add_argument(
"--issue-command",
choices=("always", "conditional", "never"),
default="conditional",
help="Whether to print extra-sandbox-paths",
)
parser.add_argument(
"--issue-stop",
choices=("always", "conditional", "never"),
default="conditional",
help="Whether to print the final empty line",
)
def symlink_parents(p: Path) -> List[Path]:
out = []
while p.is_symlink() and p not in out:
p = p.readlink()
out.append(p)
return out
def entrypoint():
if __name__ != "__main__":
return
args = parser.parse_args()
drv_path = args.derivation_path
if not Path(drv_path).exists():
print(
f"[E] {drv_path} doesn't exist."
" This may happen with the remote builds."
" Exiting the hook",
file=stderr,
)
proc = subprocess.run(
[
CONFIG["nixExe"],
"show-derivation",
drv_path,
],
capture_output=True,
)
try:
drv = json.loads(proc.stdout)
except json.JSONDecodeError:
print(
"[E] Couldn't parse the output of"
"`nix show-derivation`"
f". Expected JSON, observed: {proc.stdout}",
file=stderr,
)
print(
textwrap.indent(proc.stdout.decode("utf8"), prefix=" " * 4),
file=stderr,
)
print("[I] Exiting the nix-required-binds hook", file=stderr)
return
[canon_drv_path] = drv.keys()
allowed_patterns = CONFIG["allowedPatterns"]
known_features = set(
chain.from_iterable(
pattern["onFeatures"] for pattern in allowed_patterns.values()
)
)
drv_env = drv[canon_drv_path].get("env", {})
features = drv_env.get("requiredSystemFeatures", [])
if isinstance(features, str):
features = features.split()
features = list(filter(known_features.__contains__, features))
patterns = list(chain.from_iterable(allowed_patterns[f]["paths"] for f in features)) # noqa: E501
roots = sorted(
set(Path(path) for pattern in patterns for path in glob.glob(pattern))
)
# the pre-build-hook command
if args.issue_command == "always" or (
args.issue_command == "conditional" and roots
):
print("extra-sandbox-paths")
# arguments, one per line
for p in roots:
guest_path, host_path = p, p
print(f"{guest_path}={host_path}")
# terminated by an empty line
something_to_terminate = args.issue_stop == "conditional" and roots
if args.issue_stop == "always" or something_to_terminate:
print()
entrypoint()

View File

@ -0,0 +1,57 @@
{ addOpenGLRunpath
, cmake
, allowedPatterns ? rec {
opengl.onFeatures = [ "opengl" ];
opengl.paths = [
addOpenGLRunpath.driverLink
"/dev/video*"
"/dev/dri"
];
cuda.onFeatures = [ "cuda" ];
cuda.paths = opengl.paths ++ [
"/dev/nvidia*"
];
}
, buildPackages
, formats
, lib
, nix
, python3
, runCommand
}:
let
confPath = (formats.pythonVars { }).generate "config.py" {
CONFIG = {
inherit allowedPatterns;
nixExe = lib.getExe nix;
};
};
pname = "nix-required-mounts";
in
runCommand pname
{
inherit confPath;
meta.mainProgram = pname;
} ''
${lib.getExe buildPackages.python3.pkgs.flake8} ${./main.py}
cat > main.py << EOF
#!${lib.getExe python3}
$(cat ${./main.py})
EOF
sed -ie '
/^entrypoint()$/ {
x ;
r ${confPath}
}' main.py
echo "entrypoint()" >> main.py
mkdir -p $out/bin
install main.py $out/bin/${pname}
''

View File

@ -0,0 +1,2 @@
[tool.black]
line-length = 79