systemd: support systemd.tmpfiles.settings
Signed-off-by: phanirithvij <phanirithvij2000@gmail.com>
This commit is contained in:
parent
a79e02428d
commit
91323fb350
4 changed files with 205 additions and 14 deletions
|
|
@ -1,6 +1,139 @@
|
||||||
{ config, lib, ... }:
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
let
|
let
|
||||||
inherit (lib) types;
|
inherit (lib)
|
||||||
|
concatStrings
|
||||||
|
concatStringsSep
|
||||||
|
getLib
|
||||||
|
literalExpression
|
||||||
|
mapAttrsToList
|
||||||
|
mkOption
|
||||||
|
types
|
||||||
|
;
|
||||||
|
# copied from nixos/modules/system/boot/systemd/tmpfiles.nix
|
||||||
|
settingsOption = {
|
||||||
|
description = ''
|
||||||
|
Declare systemd-tmpfiles rules to create, delete, and clean up volatile
|
||||||
|
and temporary files and directories.
|
||||||
|
|
||||||
|
Even though the service is called `*tmp*files` you can also create
|
||||||
|
persistent files.
|
||||||
|
'';
|
||||||
|
example = {
|
||||||
|
"10-mypackage" = {
|
||||||
|
"/var/lib/my-service/statefolder".d = {
|
||||||
|
mode = "0755";
|
||||||
|
user = "root";
|
||||||
|
group = "root";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
default = { };
|
||||||
|
type = types.attrsOf (
|
||||||
|
types.attrsOf (
|
||||||
|
types.attrsOf (
|
||||||
|
types.submodule (
|
||||||
|
{ name, ... }:
|
||||||
|
{
|
||||||
|
options = {
|
||||||
|
type = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = name;
|
||||||
|
example = "d";
|
||||||
|
description = ''
|
||||||
|
The type of operation to perform on the file.
|
||||||
|
|
||||||
|
The type consists of a single letter and optionally one or more
|
||||||
|
modifier characters.
|
||||||
|
|
||||||
|
Please see the upstream documentation for the available types and
|
||||||
|
more details:
|
||||||
|
<https://www.freedesktop.org/software/systemd/man/tmpfiles.d>
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
mode = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "-";
|
||||||
|
example = "0755";
|
||||||
|
description = ''
|
||||||
|
The file access mode to use when creating this file or directory.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
user = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "-";
|
||||||
|
example = "root";
|
||||||
|
description = ''
|
||||||
|
The user of the file.
|
||||||
|
|
||||||
|
This may either be a numeric ID or a user/group name.
|
||||||
|
|
||||||
|
If omitted or when set to `"-"`, the user and group of the user who
|
||||||
|
invokes systemd-tmpfiles is used.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
group = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "-";
|
||||||
|
example = "root";
|
||||||
|
description = ''
|
||||||
|
The group of the file.
|
||||||
|
|
||||||
|
This may either be a numeric ID or a user/group name.
|
||||||
|
|
||||||
|
If omitted or when set to `"-"`, the user and group of the user who
|
||||||
|
invokes systemd-tmpfiles is used.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
age = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "-";
|
||||||
|
example = "10d";
|
||||||
|
description = ''
|
||||||
|
Delete a file when it reaches a certain age.
|
||||||
|
|
||||||
|
If a file or directory is older than the current time minus the age
|
||||||
|
field, it is deleted.
|
||||||
|
|
||||||
|
If set to `"-"` no automatic clean-up is done.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
argument = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "";
|
||||||
|
example = "";
|
||||||
|
description = ''
|
||||||
|
An argument whose meaning depends on the type of operation.
|
||||||
|
|
||||||
|
Please see the upstream documentation for the meaning of this
|
||||||
|
parameter in different situations:
|
||||||
|
<https://www.freedesktop.org/software/systemd/man/tmpfiles.d>
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
# generates a single entry for a tmpfiles.d rule
|
||||||
|
settingsEntryToRule = path: entry: ''
|
||||||
|
'${entry.type}' '${path}' '${entry.mode}' '${entry.user}' '${entry.group}' '${entry.age}' ${entry.argument}
|
||||||
|
'';
|
||||||
|
|
||||||
|
# generates a list of tmpfiles.d rules from the attrs (paths) under tmpfiles.settings.<name>
|
||||||
|
pathsToRules = mapAttrsToList (
|
||||||
|
path: types: concatStrings (mapAttrsToList (_type: settingsEntryToRule path) types)
|
||||||
|
);
|
||||||
|
|
||||||
|
mkRuleFileContent = paths: concatStrings (pathsToRules paths);
|
||||||
|
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
options = {
|
options = {
|
||||||
|
|
@ -15,13 +148,60 @@ in
|
||||||
for the exact format.
|
for the exact format.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
systemd.tmpfiles.settings = lib.mkOption settingsOption;
|
||||||
|
|
||||||
|
systemd.tmpfiles.packages = mkOption {
|
||||||
|
type = types.listOf types.package;
|
||||||
|
default = [ ];
|
||||||
|
example = literalExpression "[ pkgs.lvm2 ]";
|
||||||
|
apply = map getLib;
|
||||||
|
description = ''
|
||||||
|
List of packages containing {command}`systemd-tmpfiles` rules.
|
||||||
|
|
||||||
|
All files ending in .conf found in
|
||||||
|
{file}`«pkg»/lib/tmpfiles.d`
|
||||||
|
will be included.
|
||||||
|
If this folder does not exist or does not contain any files an error will be returned instead.
|
||||||
|
|
||||||
|
If a {file}`lib` output is available, rules are searched there and only there.
|
||||||
|
If there is no {file}`lib` output it will fall back to {file}`out`
|
||||||
|
and if that does not exist either, the default output will be used.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
config = {
|
config = {
|
||||||
environment.etc."tmpfiles.d/00-system-manager.conf".text = ''
|
environment.etc = {
|
||||||
# This file is created automatically and should not be modified.
|
"tmpfiles.d".source = pkgs.symlinkJoin {
|
||||||
# Please change the option ‘systemd.tmpfiles.rules’ instead.
|
name = "tmpfiles.d";
|
||||||
${lib.concatStringsSep "\n" config.systemd.tmpfiles.rules}
|
paths = map (p: p + "/lib/tmpfiles.d") config.systemd.tmpfiles.packages;
|
||||||
'';
|
postBuild = ''
|
||||||
|
for i in $(cat $pathsPath); do
|
||||||
|
(test -d "$i" && test $(ls "$i"/*.conf | wc -l) -ge 1) || (
|
||||||
|
echo "ERROR: The path '$i' from systemd.tmpfiles.packages contains no *.conf files."
|
||||||
|
exit 1
|
||||||
|
)
|
||||||
|
done
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
systemd.tmpfiles.packages =
|
||||||
|
[
|
||||||
|
(pkgs.writeTextFile {
|
||||||
|
name = "system-manager-tmpfiles.d";
|
||||||
|
destination = "/lib/tmpfiles.d/00-system-manager.conf";
|
||||||
|
text = ''
|
||||||
|
# This file is created automatically and should not be modified.
|
||||||
|
# Please change the option ‘systemd.tmpfiles.rules’ instead.
|
||||||
|
|
||||||
|
${concatStringsSep "\n" config.systemd.tmpfiles.rules}
|
||||||
|
'';
|
||||||
|
})
|
||||||
|
]
|
||||||
|
++ (mapAttrsToList (
|
||||||
|
name: paths: pkgs.writeTextDir "lib/tmpfiles.d/${name}.conf" (mkRuleFileContent paths)
|
||||||
|
) config.systemd.tmpfiles.settings);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -82,7 +82,7 @@ pub fn activate(store_path: &StorePath, ephemeral: bool) -> Result<()> {
|
||||||
match etc_files::activate(store_path, old_state.file_tree, ephemeral) {
|
match etc_files::activate(store_path, old_state.file_tree, ephemeral) {
|
||||||
Ok(etc_tree) => {
|
Ok(etc_tree) => {
|
||||||
log::info!("Activating tmp files...");
|
log::info!("Activating tmp files...");
|
||||||
match tmp_files::activate() {
|
match tmp_files::activate(&etc_tree) {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
log::debug!("Successfully created tmp files");
|
log::debug!("Successfully created tmp files");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,11 +27,11 @@ impl FileStatus {
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct FileTree {
|
pub struct FileTree {
|
||||||
status: FileStatus,
|
status: FileStatus,
|
||||||
path: PathBuf,
|
pub(crate) path: PathBuf,
|
||||||
// TODO directories and files are now both represented as a string associated with a nested
|
// TODO directories and files are now both represented as a string associated with a nested
|
||||||
// map. For files the nested map is simple empty.
|
// map. For files the nested map is simple empty.
|
||||||
// We could potentially optimise this.
|
// We could potentially optimise this.
|
||||||
nested: HashMap<String, FileTree>,
|
pub(crate) nested: HashMap<String, FileTree>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AsRef<FileTree> for FileTree {
|
impl AsRef<FileTree> for FileTree {
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,26 @@
|
||||||
use crate::activate;
|
use crate::activate;
|
||||||
|
use crate::activate::etc_files::FileTree;
|
||||||
|
|
||||||
use super::ActivationResult;
|
use super::ActivationResult;
|
||||||
use std::process;
|
use std::process;
|
||||||
|
|
||||||
type TmpFilesActivationResult = ActivationResult<()>;
|
type TmpFilesActivationResult = ActivationResult<()>;
|
||||||
|
|
||||||
pub fn activate() -> TmpFilesActivationResult {
|
pub fn activate(etc_tree: &FileTree) -> TmpFilesActivationResult {
|
||||||
|
let conf_files = etc_tree
|
||||||
|
.nested
|
||||||
|
.get("etc")
|
||||||
|
.unwrap()
|
||||||
|
.nested
|
||||||
|
.get("tmpfiles.d")
|
||||||
|
.unwrap()
|
||||||
|
.nested
|
||||||
|
.iter()
|
||||||
|
.map(|(_, node)| node.path.to_string_lossy().to_string())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
let mut cmd = process::Command::new("systemd-tmpfiles");
|
let mut cmd = process::Command::new("systemd-tmpfiles");
|
||||||
cmd.arg("--create")
|
cmd.arg("--create").arg("--remove").args(conf_files);
|
||||||
.arg("--remove")
|
log::debug!("running {:#?}", cmd);
|
||||||
.arg("/etc/tmpfiles.d/00-system-manager.conf");
|
|
||||||
let output = cmd
|
let output = cmd
|
||||||
.stdout(process::Stdio::inherit())
|
.stdout(process::Stdio::inherit())
|
||||||
.stderr(process::Stdio::inherit())
|
.stderr(process::Stdio::inherit())
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue