From a7142f3bc6a5bb69ac640a9af23231e6264dd971 Mon Sep 17 00:00:00 2001 From: Roman Zaynetdinov Date: Tue, 8 Apr 2025 17:03:09 +0300 Subject: [PATCH] Configure rsyslog for logs export using the spec (#11338) - Work on https://github.com/neondatabase/cloud/issues/24896 - Cplane part https://github.com/neondatabase/cloud/pull/26808 Instead of reconfiguring rsyslog via an API endpoint [we have agreed](https://neondb.slack.com/archives/C04DGM6SMTM/p1743513810964509?thread_ts=1743170369.865859&cid=C04DGM6SMTM) to have a new `logs_export_host` field as part of the compute spec. --------- Co-authored-by: Tristan Partin --- compute_tools/src/compute.rs | 15 +++++------ compute_tools/src/config.rs | 4 +-- compute_tools/src/http/openapi_spec.yaml | 30 ---------------------- compute_tools/src/http/routes/configure.rs | 27 +------------------ compute_tools/src/http/server.rs | 1 - compute_tools/src/rsyslog.rs | 20 +-------------- control_plane/src/endpoint.rs | 1 + libs/compute_api/src/requests.rs | 6 ----- libs/compute_api/src/spec.rs | 7 ++--- 9 files changed, 15 insertions(+), 96 deletions(-) diff --git a/compute_tools/src/compute.rs b/compute_tools/src/compute.rs index 70b91c781a..9dfcde1dbc 100644 --- a/compute_tools/src/compute.rs +++ b/compute_tools/src/compute.rs @@ -661,15 +661,8 @@ impl ComputeNode { } // Configure and start rsyslog for Postgres logs export - if self.has_feature(ComputeFeature::PostgresLogsExport) { - if let Some(ref project_id) = pspec.spec.cluster.cluster_id { - let host = PostgresLogsRsyslogConfig::default_host(project_id); - let conf = PostgresLogsRsyslogConfig::new(Some(&host)); - configure_postgres_logs_export(conf)?; - } else { - warn!("not configuring rsyslog for Postgres logs export: project ID is missing") - } - } + let conf = PostgresLogsRsyslogConfig::new(pspec.spec.logs_export_host.as_deref()); + configure_postgres_logs_export(conf)?; // Launch remaining service threads let _monitor_handle = launch_monitor(self); @@ -1573,6 +1566,10 @@ impl ComputeNode { }); } + // Reconfigure rsyslog for Postgres logs export + let conf = PostgresLogsRsyslogConfig::new(spec.logs_export_host.as_deref()); + configure_postgres_logs_export(conf)?; + // Write new config let pgdata_path = Path::new(&self.params.pgdata); config::write_postgres_conf( diff --git a/compute_tools/src/config.rs b/compute_tools/src/config.rs index 614ab076ff..92939f816c 100644 --- a/compute_tools/src/config.rs +++ b/compute_tools/src/config.rs @@ -7,7 +7,7 @@ use std::io::prelude::*; use std::path::Path; use compute_api::responses::TlsConfig; -use compute_api::spec::{ComputeAudit, ComputeFeature, ComputeMode, ComputeSpec, GenericOption}; +use compute_api::spec::{ComputeAudit, ComputeMode, ComputeSpec, GenericOption}; use crate::pg_helpers::{ GenericOptionExt, GenericOptionsSearch, PgOptionsSerialize, escape_conf_value, @@ -255,7 +255,7 @@ pub fn write_postgres_conf( // We need Postgres to send logs to rsyslog so that we can forward them // further to customers' log aggregation systems. - if spec.features.contains(&ComputeFeature::PostgresLogsExport) { + if spec.logs_export_host.is_some() { writeln!(file, "log_destination='stderr,syslog'")?; } diff --git a/compute_tools/src/http/openapi_spec.yaml b/compute_tools/src/http/openapi_spec.yaml index 7c8f72440f..bbdb7d0917 100644 --- a/compute_tools/src/http/openapi_spec.yaml +++ b/compute_tools/src/http/openapi_spec.yaml @@ -306,36 +306,6 @@ paths: schema: $ref: "#/components/schemas/GenericError" - /configure_telemetry: - post: - tags: - - Configure - summary: Configure rsyslog - description: | - This API endpoint configures rsyslog to forward Postgres logs - to a specified otel collector. - operationId: configureTelemetry - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - logs_export_host: - type: string - description: | - Hostname and the port of the otel collector. Leave empty to disable logs forwarding. - Example: config-shy-breeze-123-collector-monitoring.neon-telemetry.svc.cluster.local:54526 - responses: - 204: - description: "Telemetry configured successfully" - 500: - content: - application/json: - schema: - $ref: "#/components/schemas/GenericError" - components: securitySchemes: JWT: diff --git a/compute_tools/src/http/routes/configure.rs b/compute_tools/src/http/routes/configure.rs index 5c9dd22c3d..3c5a6a6d41 100644 --- a/compute_tools/src/http/routes/configure.rs +++ b/compute_tools/src/http/routes/configure.rs @@ -1,11 +1,9 @@ use std::sync::Arc; -use axum::body::Body; use axum::extract::State; use axum::response::Response; -use compute_api::requests::{ConfigurationRequest, ConfigureTelemetryRequest}; +use compute_api::requests::ConfigurationRequest; use compute_api::responses::{ComputeStatus, ComputeStatusResponse}; -use compute_api::spec::ComputeFeature; use http::StatusCode; use tokio::task; use tracing::info; @@ -13,7 +11,6 @@ use tracing::info; use crate::compute::{ComputeNode, ParsedSpec}; use crate::http::JsonResponse; use crate::http::extract::Json; -use crate::rsyslog::{PostgresLogsRsyslogConfig, configure_postgres_logs_export}; // Accept spec in JSON format and request compute configuration. If anything // goes wrong after we set the compute status to `ConfigurationPending` and @@ -95,25 +92,3 @@ pub(in crate::http) async fn configure( JsonResponse::success(StatusCode::OK, body) } - -pub(in crate::http) async fn configure_telemetry( - State(compute): State>, - request: Json, -) -> Response { - if !compute.has_feature(ComputeFeature::PostgresLogsExport) { - return JsonResponse::error( - StatusCode::PRECONDITION_FAILED, - "Postgres logs export feature is not enabled".to_string(), - ); - } - - let conf = PostgresLogsRsyslogConfig::new(request.logs_export_host.as_deref()); - if let Err(err) = configure_postgres_logs_export(conf) { - return JsonResponse::error(StatusCode::INTERNAL_SERVER_ERROR, err.to_string()); - } - - Response::builder() - .status(StatusCode::NO_CONTENT) - .body(Body::from("")) - .unwrap() -} diff --git a/compute_tools/src/http/server.rs b/compute_tools/src/http/server.rs index 179369e3ef..10f767e97c 100644 --- a/compute_tools/src/http/server.rs +++ b/compute_tools/src/http/server.rs @@ -87,7 +87,6 @@ impl From<&Server> for Router> { let authenticated_router = Router::>::new() .route("/check_writability", post(check_writability::is_writable)) .route("/configure", post(configure::configure)) - .route("/configure_telemetry", post(configure::configure_telemetry)) .route("/database_schema", get(database_schema::get_schema_dump)) .route("/dbs_and_roles", get(dbs_and_roles::get_catalog_objects)) .route("/insights", get(insights::get_insights)) diff --git a/compute_tools/src/rsyslog.rs b/compute_tools/src/rsyslog.rs index 80594db3f1..ba08302df2 100644 --- a/compute_tools/src/rsyslog.rs +++ b/compute_tools/src/rsyslog.rs @@ -119,16 +119,9 @@ impl<'a> PostgresLogsRsyslogConfig<'a> { }; Ok(config_content) } - - /// Returns the default host for otel collector that receives Postgres logs - pub fn default_host(project_id: &str) -> String { - format!( - "config-{}-collector.neon-telemetry.svc.cluster.local:10514", - project_id - ) - } } +/// Writes rsyslogd configuration for Postgres logs export and restarts rsyslog. pub fn configure_postgres_logs_export(conf: PostgresLogsRsyslogConfig) -> Result<()> { let new_config = conf.build()?; let current_config = PostgresLogsRsyslogConfig::current_config()?; @@ -261,16 +254,5 @@ mod tests { let res = conf.build(); assert!(res.is_err()); } - - { - // Verify config with default host - let host = PostgresLogsRsyslogConfig::default_host("shy-breeze-123"); - let conf = PostgresLogsRsyslogConfig::new(Some(&host)); - let res = conf.build(); - assert!(res.is_ok()); - let conf_str = res.unwrap(); - assert!(conf_str.contains(r#"shy-breeze-123"#)); - assert!(conf_str.contains(r#"port="10514""#)); - } } } diff --git a/control_plane/src/endpoint.rs b/control_plane/src/endpoint.rs index b46d616827..3137bde161 100644 --- a/control_plane/src/endpoint.rs +++ b/control_plane/src/endpoint.rs @@ -670,6 +670,7 @@ impl Endpoint { reconfigure_concurrency: self.reconfigure_concurrency, drop_subscriptions_before_start: self.drop_subscriptions_before_start, audit_log_level: ComputeAudit::Disabled, + logs_export_host: None::, }; // this strange code is needed to support respec() in tests diff --git a/libs/compute_api/src/requests.rs b/libs/compute_api/src/requests.rs index d88451c549..3fbdfcf83f 100644 --- a/libs/compute_api/src/requests.rs +++ b/libs/compute_api/src/requests.rs @@ -30,9 +30,3 @@ pub struct SetRoleGrantsRequest { pub privileges: Vec, pub role: PgIdent, } - -/// Request of the /configure_telemetry API -#[derive(Debug, Deserialize, Serialize)] -pub struct ConfigureTelemetryRequest { - pub logs_export_host: Option, -} diff --git a/libs/compute_api/src/spec.rs b/libs/compute_api/src/spec.rs index cff1f4c89a..994a665a88 100644 --- a/libs/compute_api/src/spec.rs +++ b/libs/compute_api/src/spec.rs @@ -168,6 +168,10 @@ pub struct ComputeSpec { /// Extensions should be present in shared_preload_libraries #[serde(default)] pub audit_log_level: ComputeAudit, + + /// Hostname and the port of the otel collector. Leave empty to disable Postgres logs forwarding. + /// Example: config-shy-breeze-123-collector-monitoring.neon-telemetry.svc.cluster.local:10514 + pub logs_export_host: Option, } /// Feature flag to signal `compute_ctl` to enable certain experimental functionality. @@ -179,9 +183,6 @@ pub enum ComputeFeature { /// track short-lived connections as user activity. ActivityMonitorExperimental, - /// Allow to configure rsyslog for Postgres logs export - PostgresLogsExport, - /// This is a special feature flag that is used to represent unknown feature flags. /// Basically all unknown to enum flags are represented as this one. See unit test /// `parse_unknown_features()` for more details.