use std::collections::BTreeMap;
use serde::Serialize;
use crate::observability::FieldValue;
pub const SIM_FAULT_EVENT_NAME: &str = "sim_fault";
#[derive(Debug, Clone, Serialize)]
pub enum SimFaultEvent {
ProcessGracefulShutdown {
ip: String,
grace_period_ms: u64,
},
ProcessForceKill {
ip: String,
},
ProcessRestart {
ip: String,
},
PartitionCreated {
from: String,
to: String,
},
PartitionHealed {
from: String,
to: String,
},
ConnectionCut {
connection_id: u64,
duration_ms: u64,
},
CutRestored {
connection_id: u64,
},
HalfOpenError {
connection_id: u64,
},
SendPartitionCreated {
ip: String,
},
RecvPartitionCreated {
ip: String,
},
RandomClose {
connection_id: u64,
},
PeerCrash {
connection_id: u64,
},
BitFlip {
connection_id: u64,
flip_count: usize,
},
StorageReadFault {
ip: String,
file_id: u64,
},
StorageWriteFault {
ip: String,
file_id: u64,
write_kind: String,
},
StorageSyncFault {
ip: String,
file_id: u64,
},
StorageCrash {
ip: String,
},
StorageWipe {
ip: String,
},
}
impl SimFaultEvent {
#[must_use]
pub fn kind(&self) -> &'static str {
match self {
Self::ProcessGracefulShutdown { .. } => "process_graceful_shutdown",
Self::ProcessForceKill { .. } => "process_force_kill",
Self::ProcessRestart { .. } => "process_restart",
Self::PartitionCreated { .. } => "partition_created",
Self::PartitionHealed { .. } => "partition_healed",
Self::ConnectionCut { .. } => "connection_cut",
Self::CutRestored { .. } => "cut_restored",
Self::HalfOpenError { .. } => "half_open_error",
Self::SendPartitionCreated { .. } => "send_partition_created",
Self::RecvPartitionCreated { .. } => "recv_partition_created",
Self::RandomClose { .. } => "random_close",
Self::PeerCrash { .. } => "peer_crash",
Self::BitFlip { .. } => "bit_flip",
Self::StorageReadFault { .. } => "storage_read_fault",
Self::StorageWriteFault { .. } => "storage_write_fault",
Self::StorageSyncFault { .. } => "storage_sync_fault",
Self::StorageCrash { .. } => "storage_crash",
Self::StorageWipe { .. } => "storage_wipe",
}
}
pub(crate) fn to_fields(&self) -> BTreeMap<String, FieldValue> {
let mut fields = BTreeMap::new();
let Ok(serde_json::Value::Object(tagged)) = serde_json::to_value(self) else {
return fields;
};
for payload in tagged.into_values() {
let serde_json::Value::Object(entries) = payload else {
continue;
};
for (key, value) in entries {
let field = match value {
serde_json::Value::Bool(b) => FieldValue::Bool(b),
serde_json::Value::Number(n) => {
if let Some(u) = n.as_u64() {
FieldValue::U64(u)
} else if let Some(i) = n.as_i64() {
FieldValue::I64(i)
} else if let Some(f) = n.as_f64() {
FieldValue::F64(f)
} else {
continue;
}
}
serde_json::Value::String(s) => FieldValue::Str(s),
_ => continue,
};
fields.insert(key, field);
}
}
fields
}
}