mirror of
https://github.com/neondatabase/neon.git
synced 2026-05-30 03:20:36 +00:00
## Problem Inbetween adding the TLS config for compute-ctl, and adding the TLS config in controlplane, we switched from using a provision flag to a bind flag. This happened to work in all of my testing in preview regions as they have no VM pool, so each bind was also a provision. However, in staging I found that the TLS config is still only processed during provision, even though it's only sent on bind. ## Summary of changes * Add a new feature flag value, `tls_experimental`, which tells postgres/pgbouncer/local_proxy to use the TLS certificates on bind. * compute_ctl on provision will be told where the certificates are, instead of being told on bind.
88 lines
3.2 KiB
Rust
88 lines
3.2 KiB
Rust
use std::sync::Arc;
|
|
|
|
use axum::extract::State;
|
|
use axum::response::Response;
|
|
use compute_api::requests::ConfigurationRequest;
|
|
use compute_api::responses::{ComputeStatus, ComputeStatusResponse};
|
|
use http::StatusCode;
|
|
use tokio::task;
|
|
use tracing::info;
|
|
|
|
use crate::compute::{ComputeNode, ParsedSpec};
|
|
use crate::http::JsonResponse;
|
|
use crate::http::extract::Json;
|
|
|
|
// Accept spec in JSON format and request compute configuration. If anything
|
|
// goes wrong after we set the compute status to `ConfigurationPending` and
|
|
// update compute state with new spec, we basically leave compute in the
|
|
// potentially wrong state. That said, it's control-plane's responsibility to
|
|
// watch compute state after reconfiguration request and to clean restart in
|
|
// case of errors.
|
|
pub(in crate::http) async fn configure(
|
|
State(compute): State<Arc<ComputeNode>>,
|
|
request: Json<ConfigurationRequest>,
|
|
) -> Response {
|
|
let pspec = match ParsedSpec::try_from(request.0.spec) {
|
|
Ok(p) => p,
|
|
Err(e) => return JsonResponse::error(StatusCode::BAD_REQUEST, e),
|
|
};
|
|
|
|
// XXX: wrap state update under lock in a code block. Otherwise, we will try
|
|
// to `Send` `mut state` into the spawned thread bellow, which will cause
|
|
// the following rustc error:
|
|
//
|
|
// error: future cannot be sent between threads safely
|
|
{
|
|
let mut state = compute.state.lock().unwrap();
|
|
if !matches!(state.status, ComputeStatus::Empty | ComputeStatus::Running) {
|
|
return JsonResponse::invalid_status(state.status);
|
|
}
|
|
|
|
// Pass the tracing span to the main thread that performs the startup,
|
|
// so that the start_compute operation is considered a child of this
|
|
// configure request for tracing purposes.
|
|
state.startup_span = Some(tracing::Span::current());
|
|
|
|
state.pspec = Some(pspec);
|
|
state.set_status(ComputeStatus::ConfigurationPending, &compute.state_changed);
|
|
drop(state);
|
|
}
|
|
|
|
// Spawn a blocking thread to wait for compute to become Running. This is
|
|
// needed to not block the main pool of workers and to be able to serve
|
|
// other requests while some particular request is waiting for compute to
|
|
// finish configuration.
|
|
let c = compute.clone();
|
|
let completed = task::spawn_blocking(move || {
|
|
let mut state = c.state.lock().unwrap();
|
|
while state.status != ComputeStatus::Running {
|
|
state = c.state_changed.wait(state).unwrap();
|
|
info!(
|
|
"waiting for compute to become {}, current status: {}",
|
|
ComputeStatus::Running,
|
|
state.status
|
|
);
|
|
|
|
if state.status == ComputeStatus::Failed {
|
|
let err = state.error.as_ref().map_or("unknown error", |x| x);
|
|
let msg = format!("compute configuration failed: {:?}", err);
|
|
return Err(msg);
|
|
}
|
|
}
|
|
|
|
Ok(())
|
|
})
|
|
.await
|
|
.unwrap();
|
|
|
|
if let Err(e) = completed {
|
|
return JsonResponse::error(StatusCode::INTERNAL_SERVER_ERROR, e);
|
|
}
|
|
|
|
// Return current compute state if everything went well.
|
|
let state = compute.state.lock().unwrap().clone();
|
|
let body = ComputeStatusResponse::from(&state);
|
|
|
|
JsonResponse::success(StatusCode::OK, body)
|
|
}
|