use std::collections::BTreeMap;
use openraft::error::{InitializeError, RaftError};
use openraft::storage::RaftStateMachine;
use openraft::{Raft, RaftTypeConfig};
use thiserror::Error;
use tracing::{info, warn};
#[derive(Debug)]
pub enum BootstrapMode<C: RaftTypeConfig> {
Fresh {
initial_members: BTreeMap<C::NodeId, C::Node>,
},
Reopen,
Join,
}
#[derive(Debug, Error)]
pub enum BootstrapError {
#[error("expected fresh cluster but raft is already initialized")]
UnexpectedExistingState,
#[error("initialize failed: {0}")]
Initialize(String),
}
pub async fn bootstrap<C, SM>(
raft: &Raft<C, SM>,
mode: BootstrapMode<C>,
) -> Result<(), BootstrapError>
where
C: RaftTypeConfig,
SM: RaftStateMachine<C>,
{
match mode {
BootstrapMode::Fresh { initial_members } => match raft.initialize(initial_members).await {
Ok(()) => {
info!("tsoracle-openraft-toolkit: raft initialized with fresh membership");
Ok(())
}
Err(RaftError::APIError(InitializeError::NotAllowed(_))) => {
Err(BootstrapError::UnexpectedExistingState)
}
Err(e) => Err(BootstrapError::Initialize(e.to_string())),
},
BootstrapMode::Reopen => {
info!("tsoracle-openraft-toolkit: reopen mode; relying on existing raft state");
Ok(())
}
BootstrapMode::Join => {
warn!("tsoracle-openraft-toolkit: join mode; node will sit as learner until promoted");
Ok(())
}
}
}