From ea3ca97b366a1fe188febe18b1e29bcc645e6fb7 Mon Sep 17 00:00:00 2001 From: r-vdp Date: Thu, 23 Apr 2026 09:27:31 +0200 Subject: [PATCH] switch-to-configuration-ng: Dispatch on new section in compare_units When exactly one section was newly introduced, the code looked up new_unit.get("Unit") first regardless of which section was actually new. If [Service] was the new section but the unit also had an unchanged [Unit] section, the [Service] contents were never inspected and a newly added ExecStart= would not trigger a restart. Dispatch on section_cmp instead and add unit tests for both the restart and reload cases. --- .../sw/switch-to-configuration-ng/src/main.rs | 70 +++++++++++++++---- 1 file changed, 56 insertions(+), 14 deletions(-) diff --git a/pkgs/by-name/sw/switch-to-configuration-ng/src/main.rs b/pkgs/by-name/sw/switch-to-configuration-ng/src/main.rs index fce4abcd997c..175b295a71f8 100644 --- a/pkgs/by-name/sw/switch-to-configuration-ng/src/main.rs +++ b/pkgs/by-name/sw/switch-to-configuration-ng/src/main.rs @@ -618,22 +618,25 @@ fn compare_units(current_unit: &UnitInfo, new_unit: &UnitInfo) -> UnitComparison // A section was introduced that was missing in the previous unit if !section_cmp.is_empty() { - if section_cmp.keys().len() == 1 - && (section_cmp.contains_key("Unit") || section_cmp.contains_key("Service")) - { - if let Some(new_unit_unit) = new_unit.get("Unit") { - for ini_key in new_unit_unit.keys() { - if !unit_section_ignores.contains_key(ini_key.as_str()) { - return UnitComparison::UnequalNeedsRestart; - } else if ini_key == "X-Reload-Triggers" { - ret = UnitComparison::UnequalNeedsReload; + if section_cmp.keys().len() == 1 { + // Dispatch on which section is actually new. + if section_cmp.contains_key("Unit") { + if let Some(new_unit_unit) = new_unit.get("Unit") { + for ini_key in new_unit_unit.keys() { + if !unit_section_ignores.contains_key(ini_key.as_str()) { + return UnitComparison::UnequalNeedsRestart; + } else if ini_key == "X-Reload-Triggers" { + ret = UnitComparison::UnequalNeedsReload; + } } } - } else if let Some(new_unit_service) = new_unit.get("Service") { - if new_unit_service.len() == 1 && new_unit_service.contains_key("ExecReload") { - ret = UnitComparison::UnequalNeedsReload; - } else { - return UnitComparison::UnequalNeedsRestart; + } else if section_cmp.contains_key("Service") { + if let Some(new_unit_service) = new_unit.get("Service") { + if new_unit_service.len() == 1 && new_unit_service.contains_key("ExecReload") { + ret = UnitComparison::UnequalNeedsReload; + } else { + return UnitComparison::UnequalNeedsRestart; + } } } else { return UnitComparison::UnequalNeedsRestart; @@ -2668,6 +2671,45 @@ invalid ) == super::UnitComparison::UnequalNeedsReload ); + // New [Service] section while [Unit] already existed: must inspect + // the [Service] section, not the (unchanged) [Unit] one. + assert!( + super::compare_units( + &HashMap::from([( + "Unit".to_string(), + HashMap::from([("Description".to_string(), vec!["x".to_string()])]) + )]), + &HashMap::from([ + ( + "Unit".to_string(), + HashMap::from([("Description".to_string(), vec!["x".to_string()])]) + ), + ( + "Service".to_string(), + HashMap::from([("ExecStart".to_string(), vec!["y".to_string()])]) + ), + ]), + ) == super::UnitComparison::UnequalNeedsRestart + ); + assert!( + super::compare_units( + &HashMap::from([( + "Unit".to_string(), + HashMap::from([("Description".to_string(), vec!["x".to_string()])]) + )]), + &HashMap::from([ + ( + "Unit".to_string(), + HashMap::from([("Description".to_string(), vec!["x".to_string()])]) + ), + ( + "Service".to_string(), + HashMap::from([("ExecReload".to_string(), vec!["y".to_string()])]) + ), + ]), + ) == super::UnitComparison::UnequalNeedsReload + ); + // ExecReload added to an existing [Service] section assert!( super::compare_units(