Fix systemd unloaded unit
This commit is contained in:
+142
-1
@@ -315,6 +315,9 @@ pub struct RestartDiagnostic {
|
||||
pub struct RestartReport {
|
||||
pub stage: RestartStage,
|
||||
pub failure: Option<RestartFailureKind>,
|
||||
pub service_failure: Option<service::RestartFailure>,
|
||||
pub service_phase: Option<service::RestartPhase>,
|
||||
pub systemd_unit: Option<String>,
|
||||
pub backup_path: Option<std::path::PathBuf>,
|
||||
pub restart_submitted: bool,
|
||||
pub restart_may_still_complete: bool,
|
||||
@@ -1713,6 +1716,7 @@ impl Application {
|
||||
let execution = service(&settings.systemd_unit, deadline);
|
||||
let job = execution.outcome;
|
||||
let submitted = execution.submitted;
|
||||
let service_phase = execution.phase;
|
||||
if job != RestartOutcome::Succeeded {
|
||||
self.active_restart_attempt = None;
|
||||
let may_complete = submitted
|
||||
@@ -1727,7 +1731,7 @@ impl Application {
|
||||
| service::RestartFailure::JobResultUnknown
|
||||
)
|
||||
);
|
||||
return restart_report(
|
||||
let mut report = restart_report(
|
||||
RestartStage::Service,
|
||||
Some(RestartFailureKind::ServiceFailed),
|
||||
Some(backup_path),
|
||||
@@ -1735,6 +1739,13 @@ impl Application {
|
||||
may_complete,
|
||||
submitted,
|
||||
);
|
||||
report.service_failure = match job {
|
||||
RestartOutcome::Failed(failure) => Some(failure),
|
||||
RestartOutcome::Waiting | RestartOutcome::Succeeded => None,
|
||||
};
|
||||
report.service_phase = Some(service_phase);
|
||||
report.systemd_unit = Some(settings.systemd_unit);
|
||||
return report;
|
||||
}
|
||||
let remaining = deadline.remaining_at(now());
|
||||
if remaining.is_zero() {
|
||||
@@ -2411,6 +2422,9 @@ fn restart_report(
|
||||
RestartReport {
|
||||
stage,
|
||||
failure,
|
||||
service_failure: None,
|
||||
service_phase: None,
|
||||
systemd_unit: None,
|
||||
backup_path,
|
||||
restart_submitted,
|
||||
restart_may_still_complete,
|
||||
@@ -4172,6 +4186,7 @@ restart_timeout_seconds = 30
|
||||
RestartExecution {
|
||||
outcome: RestartOutcome::Succeeded,
|
||||
submitted: true,
|
||||
phase: crate::service::RestartPhase::WaitForJob,
|
||||
}
|
||||
},
|
||||
|_, _| {
|
||||
@@ -4210,6 +4225,7 @@ restart_timeout_seconds = 30
|
||||
RestartExecution {
|
||||
outcome: RestartOutcome::Succeeded,
|
||||
submitted: true,
|
||||
phase: crate::service::RestartPhase::WaitForJob,
|
||||
}
|
||||
},
|
||||
|_, _| Err(TransportError::Transport),
|
||||
@@ -4250,6 +4266,7 @@ restart_timeout_seconds = 30
|
||||
RestartExecution {
|
||||
outcome: RestartOutcome::Succeeded,
|
||||
submitted: true,
|
||||
phase: crate::service::RestartPhase::WaitForJob,
|
||||
}
|
||||
},
|
||||
|interface, remaining| {
|
||||
@@ -4327,6 +4344,7 @@ restart_timeout_seconds = 30
|
||||
RestartExecution {
|
||||
outcome: RestartOutcome::Succeeded,
|
||||
submitted: true,
|
||||
phase: crate::service::RestartPhase::WaitForJob,
|
||||
}
|
||||
},
|
||||
|_, _| Ok(observation),
|
||||
@@ -4445,6 +4463,7 @@ restart_timeout_seconds = 30
|
||||
|_, _| RestartExecution {
|
||||
outcome: RestartOutcome::Succeeded,
|
||||
submitted: true,
|
||||
phase: crate::service::RestartPhase::WaitForJob,
|
||||
},
|
||||
|_, _| Ok(incomplete),
|
||||
|store, saved, backup| store.install(saved, backup),
|
||||
@@ -4513,6 +4532,7 @@ restart_timeout_seconds = 30
|
||||
|_, _| RestartExecution {
|
||||
outcome: RestartOutcome::Failed(RestartFailure::WaitTimedOutMayStillComplete),
|
||||
submitted: true,
|
||||
phase: crate::service::RestartPhase::WaitForJob,
|
||||
},
|
||||
|_, _| {
|
||||
runtime_called.set(true);
|
||||
@@ -4548,6 +4568,7 @@ restart_timeout_seconds = 30
|
||||
RestartExecution {
|
||||
outcome: RestartOutcome::Succeeded,
|
||||
submitted: true,
|
||||
phase: crate::service::RestartPhase::WaitForJob,
|
||||
}
|
||||
},
|
||||
|_, _| {
|
||||
@@ -4595,6 +4616,7 @@ restart_timeout_seconds = 30
|
||||
RestartExecution {
|
||||
outcome: RestartOutcome::Succeeded,
|
||||
submitted: true,
|
||||
phase: crate::service::RestartPhase::WaitForJob,
|
||||
}
|
||||
},
|
||||
|_, remaining| {
|
||||
@@ -4660,6 +4682,7 @@ restart_timeout_seconds = 30
|
||||
|_, _| RestartExecution {
|
||||
outcome: RestartOutcome::Succeeded,
|
||||
submitted: true,
|
||||
phase: crate::service::RestartPhase::WaitForJob,
|
||||
},
|
||||
|_, _| Err(error),
|
||||
|store, saved, backup| {
|
||||
@@ -4698,6 +4721,7 @@ restart_timeout_seconds = 30
|
||||
|_, _| RestartExecution {
|
||||
outcome: RestartOutcome::Failed(failure),
|
||||
submitted: true,
|
||||
phase: crate::service::RestartPhase::WaitForJob,
|
||||
},
|
||||
|_, _| unreachable!("terminal service failure must stop before runtime read"),
|
||||
|_, _, _| unreachable!("terminal service failure must stop before persistence"),
|
||||
@@ -4710,6 +4734,120 @@ restart_timeout_seconds = 30
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn application_report_preserves_every_service_failure_and_operation_phase() {
|
||||
use crate::service::RestartPhase;
|
||||
|
||||
let cases = [
|
||||
(RestartFailure::JobFailed, RestartPhase::WaitForJob, true),
|
||||
(
|
||||
RestartFailure::JobDependency,
|
||||
RestartPhase::WaitForJob,
|
||||
true,
|
||||
),
|
||||
(RestartFailure::JobTimedOut, RestartPhase::WaitForJob, true),
|
||||
(RestartFailure::JobCanceled, RestartPhase::WaitForJob, true),
|
||||
(RestartFailure::JobSkipped, RestartPhase::WaitForJob, true),
|
||||
(
|
||||
RestartFailure::JobResultUnknown,
|
||||
RestartPhase::WaitForJob,
|
||||
true,
|
||||
),
|
||||
(
|
||||
RestartFailure::BusDisconnected,
|
||||
RestartPhase::Connect,
|
||||
false,
|
||||
),
|
||||
(
|
||||
RestartFailure::ManagerOwnerChanged,
|
||||
RestartPhase::WaitForJob,
|
||||
true,
|
||||
),
|
||||
(
|
||||
RestartFailure::ManagerOwnerChanged,
|
||||
RestartPhase::RequestRestart,
|
||||
true,
|
||||
),
|
||||
(
|
||||
RestartFailure::SubscriptionFailed,
|
||||
RestartPhase::Subscribe,
|
||||
false,
|
||||
),
|
||||
(
|
||||
RestartFailure::UnitResolutionFailed,
|
||||
RestartPhase::ResolveUnit,
|
||||
false,
|
||||
),
|
||||
(
|
||||
RestartFailure::PermissionDenied,
|
||||
RestartPhase::ResolveUnit,
|
||||
false,
|
||||
),
|
||||
(
|
||||
RestartFailure::RequestFailed,
|
||||
RestartPhase::RequestRestart,
|
||||
false,
|
||||
),
|
||||
(
|
||||
RestartFailure::WaitTimedOutMayStillComplete,
|
||||
RestartPhase::WaitForJob,
|
||||
true,
|
||||
),
|
||||
(
|
||||
RestartFailure::EarlyEventBufferFull,
|
||||
RestartPhase::WaitForJob,
|
||||
true,
|
||||
),
|
||||
(
|
||||
RestartFailure::InvalidJobPath,
|
||||
RestartPhase::WaitForJob,
|
||||
true,
|
||||
),
|
||||
];
|
||||
|
||||
let root = tempfile::tempdir().expect("temp directory");
|
||||
let (mut app, _) = prepare_restartable(root.path());
|
||||
for (failure, phase, submitted) in cases {
|
||||
let preview = app.preview_restart().expect("preview saved generation");
|
||||
let report = app.restart_with_adapters(
|
||||
preview,
|
||||
RestartChoice::RestartSavedState,
|
||||
|_, _| RestartExecution {
|
||||
outcome: RestartOutcome::Failed(failure),
|
||||
submitted,
|
||||
phase,
|
||||
},
|
||||
|_, _| unreachable!("service failure must stop before runtime read"),
|
||||
|_, _, _| unreachable!("service failure must stop before persistence"),
|
||||
);
|
||||
assert_eq!(report.failure, Some(RestartFailureKind::ServiceFailed));
|
||||
assert_eq!(report.service_failure, Some(failure));
|
||||
assert_eq!(report.service_phase, Some(phase));
|
||||
assert_eq!(report.systemd_unit.as_deref(), Some("wg-quick@wg0.service"));
|
||||
assert_eq!(report.restart_submitted, submitted);
|
||||
if failure == RestartFailure::ManagerOwnerChanged
|
||||
&& phase == RestartPhase::RequestRestart
|
||||
{
|
||||
assert!(report.restart_may_still_complete);
|
||||
assert!(report.manual_recovery_required);
|
||||
}
|
||||
assert_eq!(
|
||||
report.restart_may_still_complete,
|
||||
submitted
|
||||
&& !matches!(
|
||||
failure,
|
||||
RestartFailure::JobFailed
|
||||
| RestartFailure::JobDependency
|
||||
| RestartFailure::JobTimedOut
|
||||
| RestartFailure::JobCanceled
|
||||
| RestartFailure::JobSkipped
|
||||
| RestartFailure::JobResultUnknown
|
||||
)
|
||||
);
|
||||
assert_eq!(app.states().applied(), &RuntimeObservation::Unknown);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn restart_mismatch_and_post_restart_write_failure_never_release_addresses() {
|
||||
let root = tempfile::tempdir().expect("temp directory");
|
||||
@@ -4724,6 +4862,7 @@ restart_timeout_seconds = 30
|
||||
|_, _| RestartExecution {
|
||||
outcome: RestartOutcome::Succeeded,
|
||||
submitted: true,
|
||||
phase: crate::service::RestartPhase::WaitForJob,
|
||||
},
|
||||
|_, _| {
|
||||
Ok(ObservedRuntime {
|
||||
@@ -4744,6 +4883,7 @@ restart_timeout_seconds = 30
|
||||
|_, _| RestartExecution {
|
||||
outcome: RestartOutcome::Succeeded,
|
||||
submitted: true,
|
||||
phase: crate::service::RestartPhase::WaitForJob,
|
||||
},
|
||||
|_, _| Ok(observation),
|
||||
|_, _, _| Err(PersistenceError::RecoveryRequired),
|
||||
@@ -4803,6 +4943,7 @@ restart_timeout_seconds = 30
|
||||
RestartExecution {
|
||||
outcome: RestartOutcome::Succeeded,
|
||||
submitted: true,
|
||||
phase: crate::service::RestartPhase::WaitForJob,
|
||||
}
|
||||
},
|
||||
|_, _| Err(TransportError::Transport),
|
||||
|
||||
Reference in New Issue
Block a user