mirror of
https://github.com/deuxfleurs-org/garage.git
synced 2026-07-26 07:58:14 +00:00
bootstrap: add --default-access-key and --default-bucket flags
This commit is contained in:
@@ -85,9 +85,18 @@ pub enum Command {
|
||||
|
||||
#[derive(StructOpt, Debug)]
|
||||
pub struct ServerOpt {
|
||||
/// Automatically configure a single-node layout in the cluster
|
||||
/// Automatically configure a single-node layout in the cluster.
|
||||
/// Garage will refuse to run if the cluster already has other nodes.
|
||||
#[structopt(long = "single-node")]
|
||||
pub(crate) single_node: bool,
|
||||
/// Configure a default S3 API key using environment variables `GARAGE_DEFAULT_ACCESS_KEY` and
|
||||
/// `GARAGE_DEFAULT_SECRET_KEY`. Requires `--single-node`.
|
||||
#[structopt(long = "default-access-key")]
|
||||
pub(crate) default_access_key: bool,
|
||||
/// Configure a default bucket using environment variable `GARAGE_DEFAULT_BUCKET`.
|
||||
/// Implies `--default-access-key`. Requires `--single-node`.
|
||||
#[structopt(long = "default-bucket")]
|
||||
pub(crate) default_bucket: bool,
|
||||
}
|
||||
|
||||
// -------------------------
|
||||
|
||||
+115
-4
@@ -50,6 +50,9 @@ pub async fn run_server(
|
||||
info!("Initializing Garage main data store...");
|
||||
let garage = Garage::new(config.clone())?;
|
||||
|
||||
// Handle --single-node, --default-bucket and --default-access-key
|
||||
initial_config(&garage, opt).await?;
|
||||
|
||||
info!("Initializing background runner...");
|
||||
let watch_cancel = watch_shutdown_signal();
|
||||
let (background, await_background_done) = BackgroundRunner::new(watch_cancel.clone());
|
||||
@@ -73,10 +76,6 @@ pub async fn run_server(
|
||||
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![];
|
||||
@@ -175,9 +174,23 @@ pub async fn run_server(
|
||||
}
|
||||
|
||||
async fn initial_config(garage: &Arc<Garage>, opt: ServerOpt) -> Result<(), Error> {
|
||||
use garage_model::bucket_alias_table::is_valid_bucket_name;
|
||||
use garage_model::bucket_table::Bucket;
|
||||
use garage_model::key_table::*;
|
||||
use garage_model::permission::BucketKeyPerm;
|
||||
use garage_rpc::layout::*;
|
||||
use garage_rpc::replication_mode::ReplicationFactor;
|
||||
use garage_table::*;
|
||||
use garage_util::time::now_msec;
|
||||
|
||||
if opt.single_node {
|
||||
if garage.replication_factor != ReplicationFactor::new(1).unwrap() {
|
||||
return Err(Error::Message(
|
||||
"Single-node mode requires replication_factor = 1 in the configuration file."
|
||||
.into(),
|
||||
));
|
||||
}
|
||||
|
||||
let layout_version = garage.system.cluster_layout().inner().current().version;
|
||||
|
||||
if layout_version > 1 {
|
||||
@@ -229,6 +242,104 @@ async fn initial_config(garage: &Arc<Garage>, opt: ServerOpt) -> Result<(), Erro
|
||||
}
|
||||
}
|
||||
|
||||
if (opt.default_bucket || opt.default_access_key) && !opt.single_node {
|
||||
return Err(Error::Message(
|
||||
"Flags --default-access-key and --default-bucket can only be used in single-node mode."
|
||||
.into(),
|
||||
));
|
||||
}
|
||||
|
||||
if opt.default_access_key || opt.default_bucket {
|
||||
let rdenv = |name: &str| {
|
||||
std::env::var(name)
|
||||
.map_err(|_| Error::Message(format!("Environment variable `{}` is not set", name)))
|
||||
};
|
||||
|
||||
// Create default access key if it does not exist
|
||||
let key_id = rdenv("GARAGE_DEFAULT_ACCESS_KEY")?;
|
||||
let secret_key = rdenv("GARAGE_DEFAULT_SECRET_KEY")?;
|
||||
|
||||
let existing_key = garage.key_table.get(&EmptyKey, &key_id).await?;
|
||||
|
||||
let key = match existing_key {
|
||||
Some(key) => {
|
||||
match key.state.as_option() {
|
||||
None => return Err(Error::Message(format!("Access key {} was deleted in the cluster, cannot add it back", key_id))),
|
||||
Some(st) if st.secret_key != secret_key => return Err(Error::Message(format!("Access key {} is associated with a secret key different than the one given in GARAGE_DEFAULT_SECRET_KEY", key_id))),
|
||||
_ => (),
|
||||
}
|
||||
|
||||
key
|
||||
}
|
||||
None => {
|
||||
info!("Creating default access key `{}`", key_id);
|
||||
|
||||
let mut key = Key::import(&key_id, &secret_key, "default access key")
|
||||
.map_err(|e| Error::Message(format!("Invalid default access key: {}", e)))?;
|
||||
key.state
|
||||
.as_option_mut()
|
||||
.unwrap()
|
||||
.allow_create_bucket
|
||||
.update(true);
|
||||
garage.key_table.insert(&key).await?;
|
||||
|
||||
key
|
||||
}
|
||||
};
|
||||
|
||||
if opt.default_bucket {
|
||||
// Create default bucket if it does not exist
|
||||
let bucket_name = rdenv("GARAGE_DEFAULT_BUCKET")?;
|
||||
|
||||
if !is_valid_bucket_name(&bucket_name, garage.config.allow_punycode) {
|
||||
return Err(Error::Message(
|
||||
"Invalid default bucket name, see S3 specification for allowed bucket names."
|
||||
.into(),
|
||||
));
|
||||
}
|
||||
|
||||
let helper = garage.locked_helper().await;
|
||||
|
||||
let bucket = match helper.bucket().resolve_global_bucket_fast(&bucket_name)? {
|
||||
Some(bucket) => bucket,
|
||||
None => {
|
||||
info!("Creating default bucket `{}`", bucket_name);
|
||||
|
||||
let bucket = Bucket::new();
|
||||
garage.bucket_table.insert(&bucket).await?;
|
||||
|
||||
helper
|
||||
.set_global_bucket_alias(bucket.id, &bucket_name)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
Error::Message(format!("Cannot create default bucket: {}", e))
|
||||
})?;
|
||||
|
||||
bucket
|
||||
}
|
||||
};
|
||||
|
||||
helper
|
||||
.set_bucket_key_permissions(
|
||||
bucket.id,
|
||||
&key.key_id,
|
||||
BucketKeyPerm {
|
||||
timestamp: now_msec(),
|
||||
allow_read: true,
|
||||
allow_write: true,
|
||||
allow_owner: true,
|
||||
},
|
||||
)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
Error::Message(format!(
|
||||
"Cannot configure permissions on default bucket: {}",
|
||||
e
|
||||
))
|
||||
})?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user