fix: report all missing setup requirements
This commit is contained in:
parent
e5ec3aef4c
commit
8a24ec7e9e
19
src/main.rs
19
src/main.rs
|
|
@ -32,27 +32,30 @@ async fn main() -> Result<(), error::BotError> {
|
||||||
.parse()
|
.parse()
|
||||||
.map_err(|e| error::BotError::Config(format!("invalid PORT: {e}")))?;
|
.map_err(|e| error::BotError::Config(format!("invalid PORT: {e}")))?;
|
||||||
let listener = tokio::net::TcpListener::bind(addr).await?;
|
let listener = tokio::net::TcpListener::bind(addr).await?;
|
||||||
|
let mut missing = Vec::new();
|
||||||
let redis_value = match std::env::var("REDIS_URL") {
|
let redis_value = match std::env::var("REDIS_URL") {
|
||||||
Ok(value) if !value.trim().is_empty() => value,
|
Ok(value) if !value.trim().is_empty() => value,
|
||||||
_ => {
|
_ => {
|
||||||
tracing::warn!("REDIS_URL is not configured; serving configuration setup mode");
|
missing.push("REDIS_URL".to_owned());
|
||||||
let app = router_configuration_setup(vec!["REDIS_URL".into()]).merge(web::router());
|
String::new()
|
||||||
axum::serve(listener, app).await?;
|
|
||||||
return Ok(());
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let encryption_key = match encryption_key_from_env() {
|
let encryption_key = match encryption_key_from_env() {
|
||||||
Ok(key) => key,
|
Ok(key) => key,
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
|
missing.push("CONFIG_ENCRYPTION_KEY".to_owned());
|
||||||
|
[0_u8; 32]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if !missing.is_empty() {
|
||||||
tracing::warn!(
|
tracing::warn!(
|
||||||
"CONFIG_ENCRYPTION_KEY is not configured or invalid; serving setup mode"
|
?missing,
|
||||||
|
"required bootstrap environment is incomplete; serving setup mode"
|
||||||
);
|
);
|
||||||
let app = router_configuration_setup(vec!["CONFIG_ENCRYPTION_KEY".into()])
|
let app = router_configuration_setup(missing).merge(web::router());
|
||||||
.merge(web::router());
|
|
||||||
axum::serve(listener, app).await?;
|
axum::serve(listener, app).await?;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
};
|
|
||||||
// The Redis URL is the only bootstrap credential in the migration path. Until
|
// The Redis URL is the only bootstrap credential in the migration path. Until
|
||||||
// the bootstrap route is wired, retain the legacy parser solely to obtain it.
|
// the bootstrap route is wired, retain the legacy parser solely to obtain it.
|
||||||
let bootstrap_config = match Config::from_env() {
|
let bootstrap_config = match Config::from_env() {
|
||||||
|
|
|
||||||
|
|
@ -866,6 +866,28 @@ mod tests {
|
||||||
assert!(!body.windows(4).any(|part| part == b"pass"));
|
assert!(!body.windows(4).any(|part| part == b"pass"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn configuration_setup_status_lists_both_bootstrap_requirements() {
|
||||||
|
let response =
|
||||||
|
router_configuration_setup(vec!["REDIS_URL".into(), "CONFIG_ENCRYPTION_KEY".into()])
|
||||||
|
.oneshot(
|
||||||
|
Request::builder()
|
||||||
|
.method("GET")
|
||||||
|
.uri("/api/status")
|
||||||
|
.body(Body::empty())
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
let body = axum::body::to_bytes(response.into_body(), usize::MAX)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
let value: serde_json::Value = serde_json::from_slice(&body).unwrap();
|
||||||
|
assert_eq!(value["missing"].as_array().unwrap().len(), 2);
|
||||||
|
assert_eq!(value["missing"][0], "REDIS_URL");
|
||||||
|
assert_eq!(value["missing"][1], "CONFIG_ENCRYPTION_KEY");
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn failed_bootstrap_does_not_consume_initialization_slot() {
|
async fn failed_bootstrap_does_not_consume_initialization_slot() {
|
||||||
let app = router_with_worker_state_runtime_bootstrap(
|
let app = router_with_worker_state_runtime_bootstrap(
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue