mirror of
https://github.com/deuxfleurs-org/garage.git
synced 2026-07-26 07:58:14 +00:00
bootstrap: add --single-node flag that creates a single-node layout
This commit is contained in:
@@ -8,7 +8,7 @@ use crate::cli::local::convert_db;
|
||||
pub enum Command {
|
||||
/// Run Garage server
|
||||
#[structopt(name = "server", version = garage_version())]
|
||||
Server,
|
||||
Server(ServerOpt),
|
||||
|
||||
/// Get network status
|
||||
#[structopt(name = "status", version = garage_version())]
|
||||
@@ -79,6 +79,17 @@ pub enum Command {
|
||||
},
|
||||
}
|
||||
|
||||
// ---------------------------
|
||||
// ---- garage server ... ----
|
||||
// ---------------------------
|
||||
|
||||
#[derive(StructOpt, Debug)]
|
||||
pub struct ServerOpt {
|
||||
/// Automatically configure a single-node layout in the cluster
|
||||
#[structopt(long = "single-node")]
|
||||
pub(crate) single_node: bool,
|
||||
}
|
||||
|
||||
// -------------------------
|
||||
// ---- garage node ... ----
|
||||
// -------------------------
|
||||
|
||||
+2
-2
@@ -158,7 +158,7 @@ fn main() {
|
||||
|
||||
async fn run(opt: Opt) -> Result<(), Error> {
|
||||
match opt.cmd {
|
||||
Command::Server => server::run_server(opt.config_file, opt.secrets).await,
|
||||
Command::Server(sopt) => server::run_server(opt.config_file, opt.secrets, sopt).await,
|
||||
Command::OfflineRepair(repair_opt) => {
|
||||
cli::local::repair::offline_repair(opt.config_file, opt.secrets, repair_opt).await
|
||||
}
|
||||
@@ -188,7 +188,7 @@ async fn run(opt: Opt) -> Result<(), Error> {
|
||||
fn init_logging(opt: &Opt) {
|
||||
if std::env::var("RUST_LOG").is_err() {
|
||||
let default_log = match &opt.cmd {
|
||||
Command::Server => "netapp=info,garage=info",
|
||||
Command::Server(_) => "netapp=info,garage=info",
|
||||
_ => "netapp=warn,garage=warn",
|
||||
};
|
||||
|
||||
|
||||
+69
-1
@@ -1,4 +1,5 @@
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
|
||||
use tokio::sync::watch;
|
||||
|
||||
@@ -16,6 +17,7 @@ use garage_api_k2v::api_server::K2VApiServer;
|
||||
|
||||
use crate::secrets::{fill_secrets, Secrets};
|
||||
use crate::tracing_setup::init_tracing;
|
||||
use crate::ServerOpt;
|
||||
|
||||
async fn wait_from(mut chan: watch::Receiver<bool>) {
|
||||
while !*chan.borrow() {
|
||||
@@ -25,7 +27,11 @@ async fn wait_from(mut chan: watch::Receiver<bool>) {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn run_server(config_file: PathBuf, secrets: Secrets) -> Result<(), Error> {
|
||||
pub async fn run_server(
|
||||
config_file: PathBuf,
|
||||
secrets: Secrets,
|
||||
opt: ServerOpt,
|
||||
) -> Result<(), Error> {
|
||||
info!("Loading configuration...");
|
||||
let config = fill_secrets(read_config(config_file)?, secrets)?;
|
||||
|
||||
@@ -67,6 +73,10 @@ pub async fn run_server(config_file: PathBuf, secrets: Secrets) -> Result<(), Er
|
||||
info!("Launching internal Garage cluster communications...");
|
||||
let run_system = tokio::spawn(garage.system.clone().run(watch_cancel.clone()));
|
||||
|
||||
// ---- Run initial configuration logic ----
|
||||
|
||||
initial_config(&garage, opt).await?;
|
||||
|
||||
// ---- Launch public-facing API servers ----
|
||||
|
||||
let mut servers = vec![];
|
||||
@@ -164,6 +174,64 @@ pub async fn run_server(config_file: PathBuf, secrets: Secrets) -> Result<(), Er
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn initial_config(garage: &Arc<Garage>, opt: ServerOpt) -> Result<(), Error> {
|
||||
use garage_rpc::layout::*;
|
||||
|
||||
if opt.single_node {
|
||||
let layout_version = garage.system.cluster_layout().inner().current().version;
|
||||
|
||||
if layout_version > 1 {
|
||||
return Err(Error::Message("Refusing to run in single-node mode: layout version is already superior to 1. Remove the --single-node flag to run the server in full mode.".into()));
|
||||
}
|
||||
|
||||
if layout_version == 0 {
|
||||
// Setup initial layout
|
||||
let mut layout = garage.system.cluster_layout().inner().clone();
|
||||
let our_id = garage.system.id;
|
||||
|
||||
// Check no other nodes are present in the system
|
||||
let nodes = garage.system.get_known_nodes();
|
||||
if nodes.iter().any(|x| x.id != our_id) {
|
||||
return Err(Error::Message("Refusing to run in single-node mode: more nodes are already present in the cluster.".into()));
|
||||
}
|
||||
|
||||
// Automatically determine this node's capacity
|
||||
let capacity = garage
|
||||
.system
|
||||
.local_status()
|
||||
.data_disk_avail
|
||||
.map(|(_avail, total)| total)
|
||||
.unwrap_or(1024 * 1024 * 1024); // Default to 1GB
|
||||
|
||||
assert!(layout.current().roles.is_empty());
|
||||
|
||||
layout.staging.get_mut().roles.clear();
|
||||
layout.staging.get_mut().roles.update_in_place(
|
||||
our_id,
|
||||
NodeRoleV(Some(NodeRole {
|
||||
zone: "dc1".to_string(),
|
||||
capacity: Some(capacity),
|
||||
tags: vec!["default".to_string()],
|
||||
})),
|
||||
);
|
||||
|
||||
let (layout, msg) = layout.apply_staged_changes(1)?;
|
||||
info!(
|
||||
"Created initial layout for single-node configuration:\n{}",
|
||||
msg.join("\n")
|
||||
);
|
||||
|
||||
garage
|
||||
.system
|
||||
.layout_manager
|
||||
.update_cluster_layout(&layout)
|
||||
.await?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
fn watch_shutdown_signal() -> watch::Receiver<bool> {
|
||||
use tokio::signal::unix::*;
|
||||
|
||||
Reference in New Issue
Block a user