1#![recursion_limit = "256"]
11
12use ::http::HeaderValue;
19use std::collections::{BTreeMap, BTreeSet};
20use std::panic::AssertUnwindSafe;
21use std::path::PathBuf;
22use std::pin::Pin;
23use std::sync::{Arc, LazyLock, Mutex};
24use std::time::{Duration, Instant};
25use std::{env, io};
26
27use anyhow::{Context, anyhow};
28use derivative::Derivative;
29use futures::FutureExt;
30use ipnet::IpNet;
31use mz_adapter::config::{
32 SystemParameterSyncClientConfig, SystemParameterSyncConfig, system_parameter_sync,
33};
34use mz_adapter::webhook::WebhookConcurrencyLimiter;
35use mz_adapter::{
36 AdapterError, Client as AdapterClient, RemoteSystemParameters, load_remote_system_parameters,
37};
38use mz_adapter_types::bootstrap_builtin_cluster_config::BootstrapBuiltinClusterConfig;
39use mz_adapter_types::dyncfgs::{
40 ENABLE_0DT_DEPLOYMENT_PANIC_AFTER_TIMEOUT, WITH_0DT_DEPLOYMENT_DDL_CHECK_INTERVAL,
41 WITH_0DT_DEPLOYMENT_MAX_WAIT,
42};
43use mz_auth::password::Password;
44use mz_authenticator::GenericOidcAuthenticator;
45use mz_build_info::{BuildInfo, build_info};
46use mz_catalog::config::ClusterReplicaSizeMap;
47use mz_catalog::durable::BootstrapArgs;
48use mz_cloud_resources::CloudResourceController;
49use mz_controller::ControllerConfig;
50use mz_dyncfg::ConfigSet;
51use mz_frontegg_auth::Authenticator as FronteggAuthenticator;
52use mz_license_keys::ValidatedLicenseKey;
53use mz_ore::future::OreFutureExt;
54use mz_ore::metrics::MetricsRegistry;
55use mz_ore::now::NowFn;
56use mz_ore::tracing::TracingHandle;
57use mz_ore::url::SensitiveUrl;
58use mz_ore::{instrument, task};
59use mz_persist_client::cache::PersistClientCache;
60use mz_persist_client::usage::StorageUsageClient;
61use mz_pgwire::MetricsConfig;
62use mz_pgwire_common::ConnectionCounter;
63use mz_repr::strconv;
64use mz_secrets::SecretsController;
65use mz_server_core::listeners::v26_32_0::ListenersConfig;
66use mz_server_core::listeners::{HttpListenerConfig, ListenerConfig, SqlListenerConfig};
67use mz_server_core::{
68 ConnectionStream, ListenerHandle, ReloadTrigger, ReloadingSslContext, ServeConfig,
69 TlsCertConfig, TlsMode,
70};
71use mz_sql::catalog::EnvironmentId;
72use mz_sql::session::vars::{Value, VarInput};
73use tokio::sync::oneshot;
74use tower_http::cors::AllowOrigin;
75use tracing::{Instrument, info, info_span};
76
77use crate::deployment::preflight::{self, CatchupConfig};
78use crate::deployment::state::DeploymentState;
79use crate::http::{HttpConfig, HttpServer, InternalRouteConfig};
80
81pub use crate::http::{SqlResponse, WebSocketAuth, WebSocketResponse};
82
83mod deployment;
84pub mod environmentd;
85pub mod http;
86mod telemetry;
87#[cfg(feature = "test")]
88pub mod test_util;
89
90pub const BUILD_INFO: BuildInfo = build_info!();
91
92#[derive(Derivative)]
94#[derivative(Debug)]
95pub struct Config {
96 pub unsafe_mode: bool,
100 pub all_features: bool,
103 pub restarted_in_place: bool,
106
107 pub tls: Option<TlsCertConfig>,
110 #[derivative(Debug = "ignore")]
112 pub tls_reload_certs: ReloadTrigger,
113 pub external_login_password_mz_system: Option<Password>,
115 pub frontegg: Option<FronteggAuthenticator>,
117 pub frontegg_oauth_issuer_url: Option<String>,
119 pub cors_allowed_origin: AllowOrigin,
122 pub cors_allowed_origin_list: Vec<HeaderValue>,
127 pub egress_addresses: Vec<IpNet>,
130 pub http_host_name: Option<String>,
136 pub internal_console_redirect_url: Option<String>,
139
140 pub controller: ControllerConfig,
143 pub secrets_controller: Arc<dyn SecretsController>,
145 pub cloud_resource_controller: Option<Arc<dyn CloudResourceController>>,
147 pub system_dyncfgs: Arc<ConfigSet>,
149
150 pub storage_usage_collection_interval: Duration,
153 pub storage_usage_retention_period: Option<Duration>,
155
156 pub catalog_config: CatalogConfig,
159 pub availability_zones: Vec<String>,
162 pub cluster_replica_sizes: ClusterReplicaSizeMap,
164 pub timestamp_oracle_url: Option<SensitiveUrl>,
166 pub segment_api_key: Option<String>,
168 pub segment_client_side: bool,
171 pub test_only_dummy_segment_client: bool,
173 pub launchdarkly_sdk_key: Option<String>,
176 pub launchdarkly_base_uri: Option<String>,
179 pub launchdarkly_key_map: BTreeMap<String, String>,
182 pub config_sync_timeout: Duration,
184 pub config_sync_loop_interval: Option<Duration>,
186 pub config_sync_file_path: Option<PathBuf>,
188
189 pub environment_id: EnvironmentId,
192 pub bootstrap_role: Option<String>,
194 pub bootstrap_default_cluster_replica_size: String,
196 pub bootstrap_default_cluster_replication_factor: u32,
198 pub bootstrap_builtin_system_cluster_config: BootstrapBuiltinClusterConfig,
200 pub bootstrap_builtin_catalog_server_cluster_config: BootstrapBuiltinClusterConfig,
202 pub bootstrap_builtin_probe_cluster_config: BootstrapBuiltinClusterConfig,
204 pub bootstrap_builtin_support_cluster_config: BootstrapBuiltinClusterConfig,
206 pub bootstrap_builtin_analytics_cluster_config: BootstrapBuiltinClusterConfig,
208 pub system_parameter_defaults: BTreeMap<String, String>,
211 pub helm_chart_version: Option<String>,
213 pub license_key: ValidatedLicenseKey,
215
216 pub aws_account_id: Option<String>,
220 pub aws_privatelink_availability_zones: Option<Vec<String>>,
222
223 pub metrics_registry: MetricsRegistry,
226 pub tracing_handle: TracingHandle,
228
229 pub now: NowFn,
232 pub force_builtin_schema_migration: Option<String>,
235}
236
237#[derive(Debug, Clone)]
239pub struct CatalogConfig {
240 pub persist_clients: Arc<PersistClientCache>,
242 pub metrics: Arc<mz_catalog::durable::Metrics>,
244}
245
246pub struct Listener<C> {
247 pub handle: ListenerHandle,
248 connection_stream: Pin<Box<dyn ConnectionStream>>,
249 config: C,
250}
251impl<C> Listener<C>
252where
253 C: ListenerConfig,
254{
255 fn bind(config: C) -> Result<Self, io::Error> {
267 let (handle, connection_stream) = mz_server_core::listen(&config.addr())?;
268 Ok(Self {
269 handle,
270 connection_stream,
271 config,
272 })
273 }
274}
275
276impl Listener<SqlListenerConfig> {
277 #[instrument(name = "environmentd::serve_sql")]
278 pub async fn serve_sql(
279 self,
280 name: String,
281 active_connection_counter: ConnectionCounter,
282 tls_reloading_context: Option<ReloadingSslContext>,
283 frontegg: Option<FronteggAuthenticator>,
284 adapter_client: AdapterClient,
285 oidc: GenericOidcAuthenticator,
286 metrics: MetricsConfig,
287 helm_chart_version: Option<String>,
288 ) -> ListenerHandle {
289 let label = leak_listener_name(&name);
290 let tls = tls_reloading_context.map(|context| mz_server_core::ReloadingTlsConfig {
291 context,
292 mode: if self.config.enable_tls {
293 TlsMode::Require
294 } else {
295 TlsMode::Allow
296 },
297 });
298
299 task::spawn(|| format!("{}_sql_server", label), {
300 let sql_server = mz_pgwire::Server::new(mz_pgwire::Config {
301 label,
302 tls,
303 adapter_client,
304 authenticator_kind: self.config.authenticator_kind,
305 frontegg,
306 oidc,
307 metrics,
308 active_connection_counter,
309 helm_chart_version,
310 allowed_roles: self.config.allowed_roles,
311 });
312 mz_server_core::serve(ServeConfig {
313 conns: self.connection_stream,
314 server: sql_server,
315 dyncfg: None,
318 })
319 });
320 self.handle
321 }
322}
323
324impl Listener<HttpListenerConfig> {
325 #[instrument(name = "environmentd::serve_http")]
326 pub async fn serve_http(self, config: HttpConfig) -> ListenerHandle {
327 let task_name = format!("{}_http_server", config.source);
328 task::spawn(|| task_name, {
329 let http_server = HttpServer::new(config);
330 mz_server_core::serve(ServeConfig {
331 conns: self.connection_stream,
332 server: http_server,
333 dyncfg: None,
336 })
337 });
338 self.handle
339 }
340}
341
342static LISTENER_NAMES: LazyLock<Mutex<BTreeSet<&'static str>>> =
345 LazyLock::new(|| Mutex::new(BTreeSet::new()));
346
347fn leak_listener_name(name: &str) -> &'static str {
356 let mut names = LISTENER_NAMES.lock().expect("lock poisoned");
357 if let Some(name) = names.get(name) {
358 return name;
359 }
360 let name: &'static str = Box::leak(name.to_owned().into_boxed_str());
361 names.insert(name);
362 name
363}
364
365pub struct Listeners {
366 pub http: BTreeMap<String, Listener<HttpListenerConfig>>,
367 pub sql: BTreeMap<String, Listener<SqlListenerConfig>>,
368}
369
370impl Listeners {
371 pub fn bind(config: ListenersConfig) -> Result<Self, io::Error> {
372 let mut sql = BTreeMap::new();
373 for (name, config) in config.sql {
374 sql.insert(name, Listener::bind(config)?);
375 }
376
377 let mut http = BTreeMap::new();
378 for (name, config) in config.http {
379 http.insert(name, Listener::bind(config)?);
380 }
381
382 Ok(Listeners { http, sql })
383 }
384
385 #[instrument(name = "environmentd::serve")]
389 pub async fn serve(self, config: Config) -> Result<Server, AdapterError> {
390 let serve_start = Instant::now();
391 info!("startup: envd serve: beginning");
392 info!("startup: envd serve: preamble beginning");
393
394 let tls_reloading_context = match config.tls {
396 Some(tls_config) => Some(tls_config.reloading_context(config.tls_reload_certs)?),
397 None => None,
398 };
399
400 let active_connection_counter = ConnectionCounter::default();
401 let (deployment_state, deployment_state_handle) = DeploymentState::new();
402
403 let webhook_concurrency_limit = WebhookConcurrencyLimiter::default();
412 let internal_route_config = Arc::new(InternalRouteConfig {
413 deployment_state_handle,
414 internal_console_redirect_url: config.internal_console_redirect_url,
415 });
416
417 let (authenticator_oidc_tx, authenticator_oidc_rx) = oneshot::channel();
418 let authenticator_oidc_rx = authenticator_oidc_rx.shared();
419 let (adapter_client_tx, adapter_client_rx) = oneshot::channel();
420 let adapter_client_rx = adapter_client_rx.shared();
421
422 let metrics_registry = config.metrics_registry.clone();
423 let metrics = http::Metrics::register_into(&metrics_registry, "mz_http");
424 let mcp_metrics = http::mcp_metrics::McpMetrics::register_into(&metrics_registry);
425 let oauth_metadata_metrics =
426 http::oauth_metadata::OauthMetadataMetrics::register_into(&metrics_registry);
427 let mut http_listener_handles = BTreeMap::new();
428 for (name, listener) in self.http {
429 let authenticator_kind = listener.config.authenticator_kind();
430 let source = leak_listener_name(&name);
431 let tls = if listener.config.enable_tls() {
432 tls_reloading_context.clone()
433 } else {
434 None
435 };
436 let http_config = HttpConfig {
437 adapter_client_rx: adapter_client_rx.clone(),
438 active_connection_counter: active_connection_counter.clone(),
439 helm_chart_version: config.helm_chart_version.clone(),
440 http_host_name: config.http_host_name.clone(),
441 frontegg_oauth_issuer_url: config.frontegg_oauth_issuer_url.clone(),
442 source,
443 tls,
444 authenticator_kind,
445 frontegg: config.frontegg.clone(),
446 oidc_rx: authenticator_oidc_rx.clone(),
447 allowed_origin: config.cors_allowed_origin.clone(),
448 allowed_origin_list: config.cors_allowed_origin_list.clone(),
449 concurrent_webhook_req: webhook_concurrency_limit.semaphore(),
450 dyncfgs: Arc::clone(&config.system_dyncfgs),
451 metrics: metrics.clone(),
452 metrics_registry: metrics_registry.clone(),
453 mcp_metrics: mcp_metrics.clone(),
454 oauth_metadata_metrics: oauth_metadata_metrics.clone(),
455 internal_route_config: Arc::clone(&internal_route_config),
456 routes_enabled: listener.config.routes,
457 replica_http_locator: Arc::clone(&config.controller.replica_http_locator),
458 };
459 http_listener_handles.insert(name.clone(), listener.serve_http(http_config).await);
460 }
461
462 info!(
463 "startup: envd serve: preamble complete in {:?}",
464 serve_start.elapsed()
465 );
466
467 let catalog_init_start = Instant::now();
468 info!("startup: envd serve: catalog init beginning");
469
470 let boot_ts = (config.now)().into();
472
473 let persist_client = config
474 .catalog_config
475 .persist_clients
476 .open(config.controller.persist_location.clone())
477 .await
478 .context("opening persist client")?;
479 let mut openable_adapter_storage = mz_catalog::durable::persist_backed_catalog_state(
480 persist_client.clone(),
481 config.environment_id.organization_id(),
482 BUILD_INFO.semver_version(),
483 Some(config.controller.deploy_generation),
484 Arc::clone(&config.catalog_config.metrics),
485 )
486 .await?;
487
488 info!(
489 "startup: envd serve: catalog init complete in {:?}",
490 catalog_init_start.elapsed()
491 );
492
493 let system_param_sync_start = Instant::now();
494 info!("startup: envd serve: system parameter sync beginning");
495 let system_parameter_sync_config =
497 match (config.launchdarkly_sdk_key, config.config_sync_file_path) {
498 (None, None) => None,
499 (None, Some(f)) => {
500 info!("Using config file path {:?}", f);
501 Some(SystemParameterSyncConfig::new(
502 config.environment_id.clone(),
503 &BUILD_INFO,
504 &config.metrics_registry,
505 config.launchdarkly_key_map,
506 SystemParameterSyncClientConfig::File { path: f },
507 ))
508 }
509 (Some(key), None) => Some(SystemParameterSyncConfig::new(
510 config.environment_id.clone(),
511 &BUILD_INFO,
512 &config.metrics_registry,
513 config.launchdarkly_key_map,
514 SystemParameterSyncClientConfig::LaunchDarkly {
515 sdk_key: key,
516 base_uri: config.launchdarkly_base_uri,
517 now_fn: config.now.clone(),
518 },
519 )),
520
521 (Some(_), Some(_)) => {
522 panic!("Cannot configure both file and Launchdarkly based config syncing")
523 }
524 };
525
526 let RemoteSystemParameters {
527 params: remote_system_parameters,
528 frontend: boot_frontend,
529 } = load_remote_system_parameters(
530 &mut openable_adapter_storage,
531 system_parameter_sync_config.clone(),
532 config.config_sync_timeout,
533 )
534 .await?;
535 info!(
536 "startup: envd serve: system parameter sync complete in {:?}",
537 system_param_sync_start.elapsed()
538 );
539
540 let preflight_checks_start = Instant::now();
541 info!("startup: envd serve: preflight checks beginning");
542
543 let with_0dt_deployment_max_wait = {
545 let cli_default = config
546 .system_parameter_defaults
547 .get(WITH_0DT_DEPLOYMENT_MAX_WAIT.name())
548 .map(|x| {
549 Duration::parse(VarInput::Flat(x)).map_err(|err| {
550 anyhow!(
551 "failed to parse default for {}: {:?}",
552 WITH_0DT_DEPLOYMENT_MAX_WAIT.name(),
553 err
554 )
555 })
556 })
557 .transpose()?;
558 let compiled_default = WITH_0DT_DEPLOYMENT_MAX_WAIT.default().clone();
559 let ld = get_ld_value(
560 WITH_0DT_DEPLOYMENT_MAX_WAIT.name(),
561 &remote_system_parameters,
562 |x| {
563 Duration::parse(VarInput::Flat(x)).map_err(|err| {
564 format!(
565 "failed to parse LD value {} for {}: {:?}",
566 x,
567 WITH_0DT_DEPLOYMENT_MAX_WAIT.name(),
568 err
569 )
570 })
571 },
572 )?;
573 let catalog = openable_adapter_storage
574 .get_0dt_deployment_max_wait()
575 .await?;
576 let computed = ld.or(catalog).or(cli_default).unwrap_or(compiled_default);
577 info!(
578 ?computed,
579 ?ld,
580 ?catalog,
581 ?cli_default,
582 ?compiled_default,
583 "determined value for {} system parameter",
584 WITH_0DT_DEPLOYMENT_MAX_WAIT.name()
585 );
586 computed
587 };
588 let with_0dt_deployment_ddl_check_interval = {
590 let cli_default = config
591 .system_parameter_defaults
592 .get(WITH_0DT_DEPLOYMENT_DDL_CHECK_INTERVAL.name())
593 .map(|x| {
594 Duration::parse(VarInput::Flat(x)).map_err(|err| {
595 anyhow!(
596 "failed to parse default for {}: {:?}",
597 WITH_0DT_DEPLOYMENT_DDL_CHECK_INTERVAL.name(),
598 err
599 )
600 })
601 })
602 .transpose()?;
603 let compiled_default = WITH_0DT_DEPLOYMENT_DDL_CHECK_INTERVAL.default().clone();
604 let ld = get_ld_value(
605 WITH_0DT_DEPLOYMENT_DDL_CHECK_INTERVAL.name(),
606 &remote_system_parameters,
607 |x| {
608 Duration::parse(VarInput::Flat(x)).map_err(|err| {
609 format!(
610 "failed to parse LD value {} for {}: {:?}",
611 x,
612 WITH_0DT_DEPLOYMENT_DDL_CHECK_INTERVAL.name(),
613 err
614 )
615 })
616 },
617 )?;
618 let catalog = openable_adapter_storage
619 .get_0dt_deployment_ddl_check_interval()
620 .await?;
621 let computed = ld.or(catalog).or(cli_default).unwrap_or(compiled_default);
622 info!(
623 ?computed,
624 ?ld,
625 ?catalog,
626 ?cli_default,
627 ?compiled_default,
628 "determined value for {} system parameter",
629 WITH_0DT_DEPLOYMENT_DDL_CHECK_INTERVAL.name()
630 );
631 computed
632 };
633
634 let enable_0dt_deployment_panic_after_timeout = {
637 let cli_default = config
638 .system_parameter_defaults
639 .get(ENABLE_0DT_DEPLOYMENT_PANIC_AFTER_TIMEOUT.name())
640 .map(|x| {
641 strconv::parse_bool(x).map_err(|err| {
642 anyhow!(
643 "failed to parse default for {}: {}",
644 ENABLE_0DT_DEPLOYMENT_PANIC_AFTER_TIMEOUT.name(),
645 err
646 )
647 })
648 })
649 .transpose()?;
650 let compiled_default = ENABLE_0DT_DEPLOYMENT_PANIC_AFTER_TIMEOUT.default().clone();
651 let ld = get_ld_value(
652 "enable_0dt_deployment_panic_after_timeout",
653 &remote_system_parameters,
654 |x| strconv::parse_bool(x).map_err(|x| x.to_string()),
655 )?;
656 let catalog = openable_adapter_storage
657 .get_enable_0dt_deployment_panic_after_timeout()
658 .await?;
659 let computed = ld.or(catalog).or(cli_default).unwrap_or(compiled_default);
660 info!(
661 %computed,
662 ?ld,
663 ?catalog,
664 ?cli_default,
665 ?compiled_default,
666 "determined value for enable_0dt_deployment_panic_after_timeout system parameter",
667 );
668 computed
669 };
670
671 let read_only = preflight::preflight_0dt(
675 openable_adapter_storage.as_mut(),
676 config.controller.deploy_generation,
677 config.restarted_in_place,
678 )
679 .await?;
680
681 let bootstrap_args = BootstrapArgs {
682 default_cluster_replica_size: config.bootstrap_default_cluster_replica_size.clone(),
683 default_cluster_replication_factor: config.bootstrap_default_cluster_replication_factor,
684 bootstrap_role: config.bootstrap_role,
685 cluster_replica_size_map: config.cluster_replica_sizes.clone(),
686 };
687
688 let (caught_up_trigger, bootstrapped) = if read_only {
689 let (caught_up_trigger, caught_up_receiver) = mz_ore::channel::trigger::channel();
690 let (bootstrapped, bootstrapped_receiver) = tokio::sync::oneshot::channel();
691 let catchup_config = CatchupConfig {
692 boot_ts,
693 environment_id: config.environment_id.clone(),
694 persist_client,
695 deploy_generation: config.controller.deploy_generation,
696 deployment_state: deployment_state.clone(),
697 catalog_metrics: Arc::clone(&config.catalog_config.metrics),
698 caught_up_max_wait: with_0dt_deployment_max_wait,
699 panic_after_timeout: enable_0dt_deployment_panic_after_timeout,
700 bootstrap_args: bootstrap_args.clone(),
701 ddl_check_interval: with_0dt_deployment_ddl_check_interval,
702 };
703 preflight::spawn_catchup(catchup_config, caught_up_receiver, bootstrapped_receiver);
704 (Some(caught_up_trigger), Some(bootstrapped))
705 } else {
706 (None, None)
707 };
708
709 info!(
710 "startup: envd serve: preflight checks complete in {:?}",
711 preflight_checks_start.elapsed()
712 );
713
714 let catalog_open_start = Instant::now();
715 info!("startup: envd serve: durable catalog open beginning");
716
717 let mut adapter_storage = if read_only {
719 let adapter_storage = openable_adapter_storage
722 .open_savepoint(boot_ts, &bootstrap_args)
723 .await?;
724 adapter_storage
729 } else {
730 let adapter_storage = openable_adapter_storage
731 .open(boot_ts, &bootstrap_args)
732 .await?;
733
734 deployment_state.set_is_leader();
738
739 adapter_storage
740 };
741
742 let bootstrapped = match bootstrapped {
743 Some(tx) => Some((tx, preflight::get_user_ids(adapter_storage.as_mut()).await?)),
744 None => None,
745 };
746
747 if !read_only {
749 config.controller.persist_clients.cfg().enable_compaction();
750 }
751
752 info!(
753 "startup: envd serve: durable catalog open complete in {:?}",
754 catalog_open_start.elapsed()
755 );
756
757 let coord_init_start = Instant::now();
758 info!("startup: envd serve: coordinator init beginning");
759
760 if !config
761 .cluster_replica_sizes
762 .0
763 .contains_key(&config.bootstrap_default_cluster_replica_size)
764 {
765 return Err(anyhow!("bootstrap default cluster replica size is unknown").into());
766 }
767 let envd_epoch = adapter_storage.epoch();
768
769 let storage_usage_client = StorageUsageClient::open(
771 config
772 .controller
773 .persist_clients
774 .open(config.controller.persist_location.clone())
775 .await
776 .context("opening storage usage client")?,
777 );
778
779 let license_key = config.license_key.clone();
781 let segment_client = config.segment_api_key.map(|api_key| {
782 mz_segment::Client::new(mz_segment::Config {
783 api_key,
784 client_side: config.segment_client_side,
785 })
786 });
787 let connection_limiter = active_connection_counter.clone();
788 let connection_limit_callback = Box::new(move |limit, superuser_reserved| {
789 connection_limiter.update_limit(limit);
790 connection_limiter.update_superuser_reserved(superuser_reserved);
791 });
792
793 let (adapter_handle, adapter_client) = mz_adapter::serve(mz_adapter::Config {
794 connection_context: config.controller.connection_context.clone(),
795 connection_limit_callback,
796 controller_config: config.controller,
797 controller_envd_epoch: envd_epoch,
798 storage: adapter_storage,
799 timestamp_oracle_url: config.timestamp_oracle_url,
800 unsafe_mode: config.unsafe_mode,
801 all_features: config.all_features,
802 build_info: &BUILD_INFO,
803 environment_id: config.environment_id.clone(),
804 metrics_registry: config.metrics_registry.clone(),
805 now: config.now,
806 secrets_controller: config.secrets_controller,
807 cloud_resource_controller: config.cloud_resource_controller,
808 cluster_replica_sizes: config.cluster_replica_sizes,
809 builtin_system_cluster_config: config.bootstrap_builtin_system_cluster_config,
810 builtin_catalog_server_cluster_config: config
811 .bootstrap_builtin_catalog_server_cluster_config,
812 builtin_probe_cluster_config: config.bootstrap_builtin_probe_cluster_config,
813 builtin_support_cluster_config: config.bootstrap_builtin_support_cluster_config,
814 builtin_analytics_cluster_config: config.bootstrap_builtin_analytics_cluster_config,
815 availability_zones: config.availability_zones,
816 system_parameter_defaults: config.system_parameter_defaults,
817 storage_usage_client,
818 storage_usage_collection_interval: config.storage_usage_collection_interval,
819 storage_usage_retention_period: config.storage_usage_retention_period,
820 segment_client: segment_client.clone(),
821 egress_addresses: config.egress_addresses,
822 remote_system_parameters,
823 aws_account_id: config.aws_account_id,
824 aws_privatelink_availability_zones: config.aws_privatelink_availability_zones,
825 webhook_concurrency_limit: webhook_concurrency_limit.clone(),
826 http_host_name: config.http_host_name,
827 tracing_handle: config.tracing_handle,
828 read_only_controllers: read_only,
829 caught_up_trigger,
830 helm_chart_version: config.helm_chart_version.clone(),
831 license_key: config.license_key,
832 external_login_password_mz_system: config.external_login_password_mz_system,
833 force_builtin_schema_migration: config.force_builtin_schema_migration,
834 })
835 .instrument(info_span!("adapter::serve"))
836 .await?;
837
838 if let Some((tx, initial_ids)) = bootstrapped {
839 let _ = tx.send(initial_ids);
841 }
842
843 let oidc = GenericOidcAuthenticator::new(adapter_client.clone());
845
846 info!(
847 "startup: envd serve: coordinator init complete in {:?}",
848 coord_init_start.elapsed()
849 );
850
851 let serve_postamble_start = Instant::now();
852 info!("startup: envd serve: postamble beginning");
853
854 authenticator_oidc_tx
856 .send(oidc.clone())
857 .expect("rx known to be live");
858 adapter_client_tx
859 .send(adapter_client.clone())
860 .expect("internal HTTP server should not drop first");
861
862 let metrics = mz_pgwire::MetricsConfig::register_into(&config.metrics_registry);
863
864 let mut sql_listener_handles = BTreeMap::new();
866 for (name, listener) in self.sql {
867 sql_listener_handles.insert(
868 name.clone(),
869 listener
870 .serve_sql(
871 name,
872 active_connection_counter.clone(),
873 tls_reloading_context.clone(),
874 config.frontegg.clone(),
875 adapter_client.clone(),
876 oidc.clone(),
877 metrics.clone(),
878 config.helm_chart_version.clone(),
879 )
880 .await,
881 );
882 }
883
884 if let Some(segment_client) = segment_client {
886 telemetry::start_reporting(telemetry::Config {
887 segment_client,
888 adapter_client: adapter_client.clone(),
889 environment_id: config.environment_id,
890 license_key: license_key.clone(),
891 helm_chart_version: config.helm_chart_version.clone(),
892 report_interval: Duration::from_secs(3600),
893 });
894 } else if config.test_only_dummy_segment_client {
895 tracing::debug!("starting telemetry reporting with a dummy segment client");
901 let segment_client = mz_segment::Client::new_dummy_client();
902 telemetry::start_reporting(telemetry::Config {
903 segment_client,
904 adapter_client: adapter_client.clone(),
905 environment_id: config.environment_id,
906 license_key: license_key.clone(),
907 helm_chart_version: config.helm_chart_version.clone(),
908 report_interval: Duration::from_secs(180),
909 });
910 }
911
912 if let Some(system_parameter_sync_config) = system_parameter_sync_config {
915 task::spawn(
916 || "system_parameter_sync",
917 AssertUnwindSafe(system_parameter_sync(
918 system_parameter_sync_config,
919 boot_frontend,
920 adapter_client.clone(),
921 config.config_sync_loop_interval,
922 ))
923 .ore_catch_unwind(),
924 );
925 }
926
927 info!(
928 "startup: envd serve: postamble complete in {:?}",
929 serve_postamble_start.elapsed()
930 );
931 info!(
932 "startup: envd serve: complete in {:?}",
933 serve_start.elapsed()
934 );
935
936 Ok(Server {
937 sql_listener_handles,
938 http_listener_handles,
939 #[cfg(feature = "test")]
940 adapter_client,
941 _adapter_handle: adapter_handle,
942 })
943 }
944}
945
946fn get_ld_value<V>(
947 name: &str,
948 remote_system_parameters: &Option<BTreeMap<String, String>>,
949 parse: impl Fn(&str) -> Result<V, String>,
950) -> Result<Option<V>, anyhow::Error> {
951 remote_system_parameters
952 .as_ref()
953 .and_then(|params| params.get(name))
954 .map(|x| {
955 parse(x).map_err(|err| anyhow!("failed to parse remote value for {}: {}", name, err))
956 })
957 .transpose()
958}
959
960pub struct Server {
962 pub sql_listener_handles: BTreeMap<String, ListenerHandle>,
964 pub http_listener_handles: BTreeMap<String, ListenerHandle>,
965 #[cfg(feature = "test")]
966 adapter_client: AdapterClient,
967 _adapter_handle: mz_adapter::Handle,
968}
969
970impl Server {
971 #[cfg(feature = "test")]
973 pub fn adapter_client(&self) -> &AdapterClient {
974 &self.adapter_client
975 }
976}