switch-to-configuration-ng: various mount-related fixes (#443001)
This commit is contained in:
@@ -91,6 +91,14 @@ in
|
||||
virtualisation.fileSystems."/".device = lib.mkForce "auto";
|
||||
};
|
||||
|
||||
automount.configuration = {
|
||||
virtualisation.fileSystems."/testauto" = {
|
||||
device = "tmpfs";
|
||||
fsType = "tmpfs";
|
||||
options = [ "x-systemd.automount" ];
|
||||
};
|
||||
};
|
||||
|
||||
swap.configuration.swapDevices = lib.mkVMOverride [
|
||||
{
|
||||
device = "/swapfile";
|
||||
@@ -627,6 +635,17 @@ in
|
||||
(pkgs.writeText "dbus-reload-dummy" "dbus reload dummy")
|
||||
];
|
||||
};
|
||||
|
||||
generators.configuration =
|
||||
{ lib, pkgs, ... }:
|
||||
{
|
||||
systemd.generators.simple-generator = pkgs.writeShellScript "simple-generator" ''
|
||||
${lib.getExe' pkgs.coreutils "cat"} >$1/simple-generated.service <<EOF
|
||||
[Service]
|
||||
ExecStart=${lib.getExe' pkgs.coreutils "sleep"} infinity
|
||||
EOF
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -826,9 +845,21 @@ in
|
||||
assert_lacks(out, "\nrestarting the following units:")
|
||||
assert_lacks(out, "\nstarting the following units:")
|
||||
assert_lacks(out, "the following new units were started:")
|
||||
# add an automount
|
||||
out = switch_to_specialisation("${machine}", "automount")
|
||||
assert_lacks(out, "stopping the following units:")
|
||||
assert_lacks(out, "\nrestarting the following units:")
|
||||
assert_lacks(out, "\nstarting the following units:")
|
||||
assert_contains(out, "the following new units were started: testauto.automount\n")
|
||||
# remove the automount
|
||||
out = switch_to_specialisation("${machine}", "")
|
||||
assert_contains(out, "stopping the following units: testauto.automount\n")
|
||||
assert_lacks(out, "reloading the following units:")
|
||||
assert_lacks(out, "\nrestarting the following units:")
|
||||
assert_lacks(out, "\nstarting the following units:")
|
||||
assert_lacks(out, "the following new units were started:")
|
||||
|
||||
with subtest("swaps"):
|
||||
switch_to_specialisation("${machine}", "")
|
||||
# add a swap
|
||||
out = switch_to_specialisation("${machine}", "swap")
|
||||
assert_lacks(out, "stopping the following units:")
|
||||
@@ -1520,5 +1551,13 @@ in
|
||||
assert_lacks(out, "\nrestarting the following units:")
|
||||
assert_lacks(out, "\nstarting the following units:")
|
||||
assert_lacks(out, "the following new units were started:")
|
||||
|
||||
with subtest("generators"):
|
||||
out = switch_to_specialisation("${machine}", "generators")
|
||||
# The service is not started by anything, so we start it manually
|
||||
machine.succeed("systemctl start simple-generated.service && systemctl is-active simple-generated.service")
|
||||
out = switch_to_specialisation("${machine}", "")
|
||||
# Assert switching to a different generation doesn't touch units created by generators
|
||||
machine.succeed("systemctl is-active simple-generated.service")
|
||||
'';
|
||||
}
|
||||
|
||||
@@ -197,17 +197,17 @@ fn required_env(var: &str) -> anyhow::Result<String> {
|
||||
std::env::var(var).with_context(|| format!("missing required environment variable ${var}"))
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct UnitState {
|
||||
struct UnitState<'a, 'b> {
|
||||
state: String,
|
||||
substate: String,
|
||||
proxy: Proxy<'a, &'b LocalConnection>,
|
||||
}
|
||||
|
||||
// Asks the currently running systemd instance via dbus which units are active. Returns a hash
|
||||
// where the key is the name of each unit and the value a hash of load, state, substate.
|
||||
fn get_active_units(
|
||||
systemd_manager: &Proxy<'_, &LocalConnection>,
|
||||
) -> Result<HashMap<String, UnitState>> {
|
||||
fn get_active_units<'a, 'b>(
|
||||
systemd_manager: &Proxy<'a, &'b LocalConnection>,
|
||||
) -> Result<HashMap<String, UnitState<'a, 'b>>> {
|
||||
let units = systemd_manager
|
||||
.list_units_by_patterns(Vec::new(), Vec::new())
|
||||
.context("Failed to list systemd units")?;
|
||||
@@ -219,29 +219,36 @@ fn get_active_units(
|
||||
id,
|
||||
_description,
|
||||
_load_state,
|
||||
active_state,
|
||||
sub_state,
|
||||
state,
|
||||
substate,
|
||||
following,
|
||||
_unit_path,
|
||||
unit_path,
|
||||
_job_id,
|
||||
_job_type,
|
||||
_job_path,
|
||||
)| {
|
||||
if following.is_empty() && active_state != "inactive" {
|
||||
Some((id, active_state, sub_state))
|
||||
let proxy = systemd_manager.connection.with_proxy(
|
||||
"org.freedesktop.systemd1",
|
||||
unit_path,
|
||||
Duration::from_millis(5000),
|
||||
);
|
||||
|
||||
if following.is_empty() && state != "inactive" {
|
||||
Some((
|
||||
id,
|
||||
UnitState {
|
||||
state,
|
||||
substate,
|
||||
proxy,
|
||||
},
|
||||
))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
},
|
||||
)
|
||||
.fold(HashMap::new(), |mut acc, (id, active_state, sub_state)| {
|
||||
acc.insert(
|
||||
id,
|
||||
UnitState {
|
||||
state: active_state,
|
||||
substate: sub_state,
|
||||
},
|
||||
);
|
||||
.fold(HashMap::new(), |mut acc, (id, unit_state)| {
|
||||
acc.insert(id, unit_state);
|
||||
|
||||
acc
|
||||
}))
|
||||
@@ -811,9 +818,12 @@ fn parse_fstab(fstab: impl BufRead) -> (HashMap<String, Filesystem>, HashMap<Str
|
||||
|
||||
// Converts a path to the name of a systemd mount unit that would be responsible for mounting this
|
||||
// path.
|
||||
fn path_to_unit_name(bin_path: &Path, path: &str) -> String {
|
||||
fn path_to_unit_name(bin_path: &Path, path: &str, is_automount: bool) -> String {
|
||||
let Ok(output) = std::process::Command::new(bin_path.join("systemd-escape"))
|
||||
.arg("--suffix=mount")
|
||||
.arg(format!(
|
||||
"--suffix={}",
|
||||
if is_automount { "automount" } else { "mount" }
|
||||
))
|
||||
.arg("-p")
|
||||
.arg(path)
|
||||
.output()
|
||||
@@ -823,7 +833,7 @@ fn path_to_unit_name(bin_path: &Path, path: &str) -> String {
|
||||
};
|
||||
|
||||
let Ok(unit) = String::from_utf8(output.stdout) else {
|
||||
eprintln!("Unable to convert systemd-espape output to valid UTF-8");
|
||||
eprintln!("Unable to convert systemd-escape output to valid UTF-8");
|
||||
die();
|
||||
};
|
||||
|
||||
@@ -1189,6 +1199,17 @@ won't take effect until you reboot the system.
|
||||
.context("Invalid regex for matching systemd unit names")?;
|
||||
|
||||
for (unit, unit_state) in ¤t_active_units {
|
||||
// Don't touch units not explicitly written by NixOS (e.g. units created by generators in
|
||||
// /run/systemd/generator*)
|
||||
if !unit_state
|
||||
.proxy
|
||||
.get("org.freedesktop.systemd1.Unit", "FragmentPath")
|
||||
.map(|fragment_path: String| fragment_path.starts_with("/etc/systemd/system"))
|
||||
.unwrap_or_default()
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
let current_unit_file = Path::new("/etc/systemd/system").join(unit);
|
||||
let new_unit_file = toplevel.join("etc/systemd/system").join(unit);
|
||||
|
||||
@@ -1319,8 +1340,10 @@ won't take effect until you reboot the system.
|
||||
.unwrap_or_default();
|
||||
|
||||
for (mountpoint, current_filesystem) in current_filesystems {
|
||||
let is_automount = current_filesystem.options.contains("x-systemd.automount");
|
||||
|
||||
// Use current version of systemctl binary before daemon is reexeced.
|
||||
let unit = path_to_unit_name(¤t_system_bin, &mountpoint);
|
||||
let unit = path_to_unit_name(¤t_system_bin, &mountpoint, is_automount);
|
||||
if let Some(new_filesystem) = new_filesystems.get(&mountpoint) {
|
||||
if current_filesystem.fs_type != new_filesystem.fs_type
|
||||
|| current_filesystem.device != new_filesystem.device
|
||||
|
||||
Reference in New Issue
Block a user