mirror of
https://github.com/NixOS/nixpkgs.git
synced 2026-06-05 21:03:40 +00:00
nixos-init: init env-generator
The env generator allows us to declaratively set environment variables via the module system for all systemd generators. This will allow us to drop systemd/0013-inherit-systemd-environment-when-calling-generators.patch
This commit is contained in:
@@ -742,6 +742,8 @@ in
|
||||
};
|
||||
|
||||
systemd = {
|
||||
generatorPath = [ cfg.package ];
|
||||
|
||||
sockets.sshd = lib.mkIf cfg.startWhenNeeded {
|
||||
description = "SSH Socket";
|
||||
wantedBy = [ "sockets.target" ];
|
||||
|
||||
@@ -233,6 +233,8 @@ let
|
||||
|
||||
proxy_env = config.networking.proxy.envVars;
|
||||
|
||||
json = pkgs.formats.json { };
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
@@ -356,6 +358,30 @@ in
|
||||
'';
|
||||
};
|
||||
|
||||
generatorEnvironment = mkOption {
|
||||
type = types.attrsOf types.str;
|
||||
default = { };
|
||||
example = {
|
||||
MY_VAR = "my-value";
|
||||
};
|
||||
description = ''
|
||||
Environment variables for systemd generators.
|
||||
|
||||
The `PATH` environment variable is populated via `systemd.generatorPath`.
|
||||
'';
|
||||
};
|
||||
|
||||
generatorPath = mkOption {
|
||||
type = types.listOf types.package;
|
||||
default = [ ];
|
||||
example = [
|
||||
pkgs.hello
|
||||
];
|
||||
description = ''
|
||||
Packages added to the `PATH` environment variable of all systemd generators.
|
||||
'';
|
||||
};
|
||||
|
||||
shutdown = mkOption {
|
||||
type = types.attrsOf types.path;
|
||||
default = { };
|
||||
@@ -636,6 +662,12 @@ in
|
||||
"systemd/user-preset/00-nixos.preset".text = ''
|
||||
ignore *
|
||||
'';
|
||||
|
||||
"systemd/generator-environment.json".source =
|
||||
json.generate "systemd-generator-environment.json" cfg.generatorEnvironment;
|
||||
|
||||
"systemd/system-environment-generators/env-generator".source =
|
||||
"${config.system.nixos-init.package}/bin/env-generator";
|
||||
};
|
||||
|
||||
services.dbus.enable = true;
|
||||
@@ -683,12 +715,7 @@ in
|
||||
systemd.managerEnvironment = {
|
||||
# Doesn't contain systemd itself - everything works so it seems to use the compiled-in value for its tools
|
||||
# util-linux is needed for the main fsck utility wrapping the fs-specific ones
|
||||
PATH = lib.makeBinPath (
|
||||
config.system.fsPackages
|
||||
++ [ cfg.package.util-linux ]
|
||||
# systemd-ssh-generator needs sshd in PATH
|
||||
++ lib.optional config.services.openssh.enable config.services.openssh.package
|
||||
);
|
||||
PATH = lib.makeBinPath (config.system.fsPackages ++ [ cfg.package.util-linux ]);
|
||||
LOCALE_ARCHIVE = "/run/current-system/sw/lib/locale/locale-archive";
|
||||
TZDIR = "/etc/zoneinfo";
|
||||
# If SYSTEMD_UNIT_PATH ends with an empty component (":"), the usual unit load path will be appended to the contents of the variable
|
||||
@@ -704,6 +731,16 @@ in
|
||||
DefaultIPAccounting = lib.mkDefault true;
|
||||
};
|
||||
|
||||
# These are needed for systemd-fstab-generator to schedule systemd-fsck@
|
||||
# units.
|
||||
systemd.generatorPath = config.system.fsPackages ++ [
|
||||
cfg.package.util-linux
|
||||
];
|
||||
|
||||
systemd.generatorEnvironment = {
|
||||
PATH = lib.makeBinPath cfg.generatorPath;
|
||||
};
|
||||
|
||||
system.requiredKernelConfig = map config.lib.kernelConfig.isEnabled [
|
||||
"DEVTMPFS"
|
||||
"CGROUPS"
|
||||
|
||||
@@ -19,6 +19,7 @@ in
|
||||
|
||||
nodes = {
|
||||
virthost = {
|
||||
environment.systemPackages = [ pkgs.jq ];
|
||||
services.openssh = {
|
||||
enable = true;
|
||||
settings.PermitRootLogin = "prohibit-password";
|
||||
@@ -48,6 +49,10 @@ in
|
||||
virthost.succeed("cp '${snakeOilEd25519PrivateKey}' ~/.ssh/id_ed25519")
|
||||
virthost.succeed("chmod 600 ~/.ssh/id_ed25519")
|
||||
|
||||
with subtest("Check the environment generator"):
|
||||
print(virthost.succeed("jq '.' /etc/systemd/generator-environment.json"))
|
||||
print(virthost.succeed("/etc/systemd/system-environment-generators/env-generator"))
|
||||
|
||||
with subtest("ssh into a container with AF_UNIX"):
|
||||
virthost.wait_for_unit("container@guest.service")
|
||||
virthost.wait_until_succeeds("ssh -i ~/.ssh/id_ed25519 unix/run/systemd/nspawn/unix-export/guest/ssh echo meow | grep meow")
|
||||
|
||||
@@ -48,6 +48,7 @@ rustPlatform.buildRustPackage (finalAttrs: {
|
||||
"initrd-init"
|
||||
"find-etc"
|
||||
"resolve-in-root"
|
||||
"env-generator"
|
||||
];
|
||||
|
||||
postInstall = ''
|
||||
|
||||
53
pkgs/by-name/ni/nixos-init/src/env_generator.rs
Normal file
53
pkgs/by-name/ni/nixos-init/src/env_generator.rs
Normal file
@@ -0,0 +1,53 @@
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
fs,
|
||||
io::{self, Write},
|
||||
};
|
||||
|
||||
use anyhow::{Context, Result};
|
||||
use serde::Deserialize;
|
||||
|
||||
const CONFIG_PATH: &str = "/etc/systemd/generator-environment.json";
|
||||
const KMSG_PATH: &str = "/dev/kmsg";
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct Config(HashMap<String, String>);
|
||||
|
||||
/// Implementation for the entrypoint of the `env-generator` binary.
|
||||
///
|
||||
/// Reads the JSON config for the systemd generator environment and prints it in KEY=VALUE format
|
||||
/// to stdout. This makes the configured environment variables available for all systemd
|
||||
/// generators.
|
||||
fn env_generator_impl() -> Result<()> {
|
||||
let content = fs::read(CONFIG_PATH).with_context(|| format!("Failed to read {CONFIG_PATH}"))?;
|
||||
let config: Config = serde_json::from_slice(&content).context("Failed to parse config")?;
|
||||
|
||||
let mut buffer = Vec::new();
|
||||
for (key, value) in config.0 {
|
||||
writeln!(&mut buffer, "{key}=\"{value}\"").context("Failed to write to buffer")?;
|
||||
}
|
||||
|
||||
let stdout = io::stdout();
|
||||
let mut locked = stdout.lock();
|
||||
locked
|
||||
.write_all(&buffer)
|
||||
.context("Failed to write to stdout")?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Entrypoint for the `env-generator` binary.
|
||||
///
|
||||
/// Generators cannot use normal logging but have to write to /dev/kmsg.
|
||||
///
|
||||
/// The return value is just here so that we can use the `main.rs` entrypoint for this binary.
|
||||
/// Errors returned from this function will not be logged and thus are meaningless.
|
||||
pub fn env_generator() -> Result<()> {
|
||||
if let Err(err) = env_generator_impl() {
|
||||
// Sometimes we do not have /dev/kmsg, e.g. inside a container
|
||||
if let Ok(mut kmsg) = fs::OpenOptions::new().write(true).open(KMSG_PATH) {
|
||||
let _ = write!(kmsg, "<3>env-generator: {err:#}");
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
mod activate;
|
||||
mod config;
|
||||
mod env_generator;
|
||||
mod find_etc;
|
||||
mod fs;
|
||||
mod init;
|
||||
@@ -14,6 +15,7 @@ use anyhow::{Context, Result, bail};
|
||||
|
||||
pub use crate::{
|
||||
activate::activate,
|
||||
env_generator::env_generator,
|
||||
find_etc::find_etc,
|
||||
init::init,
|
||||
initrd_init::initrd_init,
|
||||
|
||||
@@ -2,7 +2,7 @@ use std::{env, io::Write, process::ExitCode};
|
||||
|
||||
use log::Level;
|
||||
|
||||
use nixos_init::{find_etc, initrd_init, resolve_in_root};
|
||||
use nixos_init::{env_generator, find_etc, initrd_init, resolve_in_root};
|
||||
|
||||
fn main() -> ExitCode {
|
||||
let arg0 = env::args()
|
||||
@@ -15,6 +15,7 @@ fn main() -> ExitCode {
|
||||
"find-etc" => find_etc,
|
||||
"resolve-in-root" => resolve_in_root,
|
||||
"initrd-init" => initrd_init,
|
||||
"env-generator" => env_generator,
|
||||
_ => {
|
||||
log::error!("Command {arg0} unknown");
|
||||
return ExitCode::FAILURE;
|
||||
|
||||
Reference in New Issue
Block a user