Fail teardown when control withdrawal fails
This commit is contained in:
parent
da7557b850
commit
a9c9cf7ab3
3 changed files with 51 additions and 11 deletions
|
|
@ -449,9 +449,10 @@ impl LifecycleAdapter for ProductionLifecycleAdapter<'_> {
|
||||||
LifecycleAction::ReleasePreparedLowerLease => self.release_prepared_lower(),
|
LifecycleAction::ReleasePreparedLowerLease => self.release_prepared_lower(),
|
||||||
LifecycleAction::GracefulSupervisorExit => self.graceful_exit(),
|
LifecycleAction::GracefulSupervisorExit => self.graceful_exit(),
|
||||||
LifecycleAction::BeginTeardown => {
|
LifecycleAction::BeginTeardown => {
|
||||||
if let Some(control) = self.published_control.take() {
|
if let Some(control) = self.published_control.as_ref() {
|
||||||
control.withdraw();
|
control.withdraw().map_err(failure)?;
|
||||||
}
|
}
|
||||||
|
self.published_control.take();
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
LifecycleAction::FinishTeardown => {
|
LifecycleAction::FinishTeardown => {
|
||||||
|
|
|
||||||
|
|
@ -1010,9 +1010,12 @@ impl PublishedControlFace {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Withdraws exact discovery and connection paths while retaining live accepted streams.
|
/// Withdraws exact discovery and connection paths while retaining live accepted streams.
|
||||||
pub fn withdraw(&self) {
|
///
|
||||||
remove_if_identity_matches(&self.paths.socket, self.socket_identity);
|
/// # Errors
|
||||||
remove_if_identity_matches(&self.paths.identity, self.identity_file_identity);
|
/// Refuses changed artifacts, removal failures, or artifacts that remain after removal.
|
||||||
|
pub fn withdraw(&self) -> Result<(), ControlError> {
|
||||||
|
remove_exact_if_identity_matches(&self.paths.socket, self.socket_identity)?;
|
||||||
|
remove_exact_if_identity_matches(&self.paths.identity, self.identity_file_identity)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Accepts and serves one TLS connection. Registered connections remain live until EOF.
|
/// Accepts and serves one TLS connection. Registered connections remain live until EOF.
|
||||||
|
|
@ -1260,7 +1263,32 @@ impl PublishedControlFace {
|
||||||
|
|
||||||
impl Drop for PublishedControlFace {
|
impl Drop for PublishedControlFace {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
self.withdraw();
|
remove_if_identity_matches(&self.paths.socket, self.socket_identity);
|
||||||
|
remove_if_identity_matches(&self.paths.identity, self.identity_file_identity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn remove_exact_if_identity_matches(
|
||||||
|
path: &Path,
|
||||||
|
expected: FileIdentity,
|
||||||
|
) -> Result<(), ControlError> {
|
||||||
|
let metadata = match std::fs::symlink_metadata(path) {
|
||||||
|
Ok(metadata) => metadata,
|
||||||
|
Err(error) if error.kind() == io::ErrorKind::NotFound => return Ok(()),
|
||||||
|
Err(error) => return Err(error.into()),
|
||||||
|
};
|
||||||
|
if FileIdentity::from_metadata(&metadata) != expected {
|
||||||
|
return Err(ControlError::InvalidPublication(
|
||||||
|
"publication artifact identity changed before withdrawal",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
std::fs::remove_file(path)?;
|
||||||
|
match std::fs::symlink_metadata(path) {
|
||||||
|
Err(error) if error.kind() == io::ErrorKind::NotFound => Ok(()),
|
||||||
|
Err(error) => Err(error.into()),
|
||||||
|
Ok(_) => Err(ControlError::InvalidPublication(
|
||||||
|
"publication artifact remained after withdrawal",
|
||||||
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ use lazaret_host_coordinator::control::{
|
||||||
};
|
};
|
||||||
use lazaret_host_coordinator::domain_store::{DomainStoreMutation, HostCoordinatorDomainStore};
|
use lazaret_host_coordinator::domain_store::{DomainStoreMutation, HostCoordinatorDomainStore};
|
||||||
use lazaret_host_coordinator::lifecycle::{
|
use lazaret_host_coordinator::lifecycle::{
|
||||||
HostCoordinatorLifecycle, LifecycleAction, LifecycleAdapter,
|
DomainPhase, HostCoordinatorLifecycle, LifecycleAction, LifecycleAdapter,
|
||||||
};
|
};
|
||||||
use lazaret_linux::filesystem::try_exclusive_flock;
|
use lazaret_linux::filesystem::try_exclusive_flock;
|
||||||
use rustix::process::getuid;
|
use rustix::process::getuid;
|
||||||
|
|
@ -44,10 +44,12 @@ impl LifecycleAdapter for ControlLifecycleAdapter {
|
||||||
action: LifecycleAction,
|
action: LifecycleAction,
|
||||||
_generation: &Generation,
|
_generation: &Generation,
|
||||||
) -> Result<(), Self::Error> {
|
) -> Result<(), Self::Error> {
|
||||||
if action == LifecycleAction::BeginTeardown
|
if action == LifecycleAction::BeginTeardown {
|
||||||
&& let Some(face) = self.publication.lock().unwrap().take()
|
let mut publication = self.publication.lock().unwrap();
|
||||||
{
|
if let Some(face) = publication.as_ref() {
|
||||||
face.withdraw();
|
face.withdraw()?;
|
||||||
|
}
|
||||||
|
publication.take();
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
@ -861,7 +863,16 @@ fn coordinated_control_session_tracks_lifecycle_and_withdraws_before_teardown()
|
||||||
Some(SessionPhase::Closed)
|
Some(SessionPhase::Closed)
|
||||||
);
|
);
|
||||||
assert!(lifecycle.is_teardown_ready());
|
assert!(lifecycle.is_teardown_ready());
|
||||||
|
std::fs::set_permissions(&directory.0, std::fs::Permissions::from_mode(0o500)).unwrap();
|
||||||
|
assert!(lifecycle.begin_teardown().is_err());
|
||||||
|
assert_eq!(lifecycle.phase(), DomainPhase::Ready);
|
||||||
|
assert!(lifecycle.is_published());
|
||||||
|
assert!(face.socket_path().exists());
|
||||||
|
assert!(face.identity_path().exists());
|
||||||
|
std::fs::set_permissions(&directory.0, std::fs::Permissions::from_mode(0o700)).unwrap();
|
||||||
lifecycle.begin_teardown().unwrap();
|
lifecycle.begin_teardown().unwrap();
|
||||||
|
assert_eq!(lifecycle.phase(), DomainPhase::Stopping);
|
||||||
|
assert!(!lifecycle.is_published());
|
||||||
assert!(!face.socket_path().exists());
|
assert!(!face.socket_path().exists());
|
||||||
assert!(!face.identity_path().exists());
|
assert!(!face.identity_path().exists());
|
||||||
assert!(std::os::unix::net::UnixStream::connect(face.socket_path()).is_err());
|
assert!(std::os::unix::net::UnixStream::connect(face.socket_path()).is_err());
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue