Implement ring comparison algorithm

This commit is contained in:
Alex Auvolat
2020-04-16 17:04:28 +02:00
parent f01c1e71b5
commit e8d750175d
3 changed files with 142 additions and 13 deletions
+70 -1
View File
@@ -61,6 +61,10 @@ pub enum Command {
/// Configure Garage node
#[structopt(name = "configure")]
Configure(ConfigureOpt),
/// Remove Garage node from cluster
#[structopt(name = "remove")]
Remove(RemoveOpt),
}
#[derive(StructOpt, Debug)]
@@ -82,6 +86,16 @@ pub struct ConfigureOpt {
n_tokens: u32,
}
#[derive(StructOpt, Debug)]
pub struct RemoveOpt {
/// Node to configure (prefix of hexadecimal node id)
node_id: String,
/// If this flag is not given, the node won't be removed
#[structopt(long = "yes")]
yes: bool,
}
#[tokio::main]
async fn main() {
let opt = Opt::from_args();
@@ -102,11 +116,20 @@ async fn main() {
let rpc_cli = RpcClient::new(&tls_config).expect("Could not create RPC client");
let resp = match opt.cmd {
Command::Server(server_opt) => server::run_server(server_opt.config_file).await,
Command::Server(server_opt) => {
// Abort on panic (same behavior as in Go)
std::panic::set_hook(Box::new(|panic_info| {
eprintln!("{}", panic_info.to_string());
std::process::abort();
}));
server::run_server(server_opt.config_file).await
}
Command::Status => cmd_status(rpc_cli, opt.rpc_host).await,
Command::Configure(configure_opt) => {
cmd_configure(rpc_cli, opt.rpc_host, configure_opt).await
}
Command::Remove(remove_opt) => cmd_remove(rpc_cli, opt.rpc_host, remove_opt).await,
};
if let Err(e) = resp {
@@ -224,3 +247,49 @@ async fn cmd_configure(
.await?;
Ok(())
}
async fn cmd_remove(
rpc_cli: RpcClient,
rpc_host: SocketAddr,
args: RemoveOpt,
) -> Result<(), Error> {
let mut config = match rpc_cli
.call(&rpc_host, &Message::PullConfig, DEFAULT_TIMEOUT)
.await?
{
Message::AdvertiseConfig(cfg) => cfg,
resp => return Err(Error::Message(format!("Invalid RPC response: {:?}", resp))),
};
let mut candidates = vec![];
for (key, _) in config.members.iter() {
if hex::encode(key).starts_with(&args.node_id) {
candidates.push(key.clone());
}
}
if candidates.len() != 1 {
return Err(Error::Message(format!(
"{} matching nodes",
candidates.len()
)));
}
if !args.yes {
return Err(Error::Message(format!(
"Add the flag --yes to really remove {:?} from the cluster",
candidates[0]
)));
}
config.members.remove(&candidates[0]);
config.version += 1;
rpc_cli
.call(
&rpc_host,
&Message::AdvertiseConfig(config),
DEFAULT_TIMEOUT,
)
.await?;
Ok(())
}