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
104 pub tls: Option<TlsCertConfig>,
107 #[derivative(Debug = "ignore")]
109 pub tls_reload_certs: ReloadTrigger,
110 pub external_login_password_mz_system: Option<Password>,
112 pub frontegg: Option<FronteggAuthenticator>,
114 pub frontegg_oauth_issuer_url: Option<String>,
116 pub cors_allowed_origin: AllowOrigin,
119 pub cors_allowed_origin_list: Vec<HeaderValue>,
124 pub egress_addresses: Vec<IpNet>,
127 pub http_host_name: Option<String>,
133 pub internal_console_redirect_url: Option<String>,
136
137 pub controller: ControllerConfig,
140 pub secrets_controller: Arc<dyn SecretsController>,
142 pub cloud_resource_controller: Option<Arc<dyn CloudResourceController>>,
144 pub system_dyncfgs: Arc<ConfigSet>,
146
147 pub storage_usage_collection_interval: Duration,
150 pub storage_usage_retention_period: Option<Duration>,
152
153 pub catalog_config: CatalogConfig,
156 pub availability_zones: Vec<String>,
159 pub cluster_replica_sizes: ClusterReplicaSizeMap,
161 pub timestamp_oracle_url: Option<SensitiveUrl>,
163 pub segment_api_key: Option<String>,
165 pub segment_client_side: bool,
168 pub test_only_dummy_segment_client: bool,
170 pub launchdarkly_sdk_key: Option<String>,
173 pub launchdarkly_base_uri: Option<String>,
176 pub launchdarkly_key_map: BTreeMap<String, String>,
179 pub config_sync_timeout: Duration,
181 pub config_sync_loop_interval: Option<Duration>,
183 pub config_sync_file_path: Option<PathBuf>,
185
186 pub environment_id: EnvironmentId,
189 pub bootstrap_role: Option<String>,
191 pub bootstrap_default_cluster_replica_size: String,
193 pub bootstrap_default_cluster_replication_factor: u32,
195 pub bootstrap_builtin_system_cluster_config: BootstrapBuiltinClusterConfig,
197 pub bootstrap_builtin_catalog_server_cluster_config: BootstrapBuiltinClusterConfig,
199 pub bootstrap_builtin_probe_cluster_config: BootstrapBuiltinClusterConfig,
201 pub bootstrap_builtin_support_cluster_config: BootstrapBuiltinClusterConfig,
203 pub bootstrap_builtin_analytics_cluster_config: BootstrapBuiltinClusterConfig,
205 pub system_parameter_defaults: BTreeMap<String, String>,
208 pub helm_chart_version: Option<String>,
210 pub license_key: ValidatedLicenseKey,
212
213 pub aws_account_id: Option<String>,
217 pub aws_privatelink_availability_zones: Option<Vec<String>>,
219
220 pub metrics_registry: MetricsRegistry,
223 pub tracing_handle: TracingHandle,
225
226 pub now: NowFn,
229 pub force_builtin_schema_migration: Option<String>,
232}
233
234#[derive(Debug, Clone)]
236pub struct CatalogConfig {
237 pub persist_clients: Arc<PersistClientCache>,
239 pub metrics: Arc<mz_catalog::durable::Metrics>,
241}
242
243pub struct Listener<C> {
244 pub handle: ListenerHandle,
245 connection_stream: Pin<Box<dyn ConnectionStream>>,
246 config: C,
247}
248impl<C> Listener<C>
249where
250 C: ListenerConfig,
251{
252 async fn bind(config: C) -> Result<Self, io::Error> {
264 let (handle, connection_stream) = mz_server_core::listen(&config.addr()).await?;
265 Ok(Self {
266 handle,
267 connection_stream,
268 config,
269 })
270 }
271}
272
273impl Listener<SqlListenerConfig> {
274 #[instrument(name = "environmentd::serve_sql")]
275 pub async fn serve_sql(
276 self,
277 name: String,
278 active_connection_counter: ConnectionCounter,
279 tls_reloading_context: Option<ReloadingSslContext>,
280 frontegg: Option<FronteggAuthenticator>,
281 adapter_client: AdapterClient,
282 oidc: GenericOidcAuthenticator,
283 metrics: MetricsConfig,
284 helm_chart_version: Option<String>,
285 ) -> ListenerHandle {
286 let label = leak_listener_name(&name);
287 let tls = tls_reloading_context.map(|context| mz_server_core::ReloadingTlsConfig {
288 context,
289 mode: if self.config.enable_tls {
290 TlsMode::Require
291 } else {
292 TlsMode::Allow
293 },
294 });
295
296 task::spawn(|| format!("{}_sql_server", label), {
297 let sql_server = mz_pgwire::Server::new(mz_pgwire::Config {
298 label,
299 tls,
300 adapter_client,
301 authenticator_kind: self.config.authenticator_kind,
302 frontegg,
303 oidc,
304 metrics,
305 active_connection_counter,
306 helm_chart_version,
307 allowed_roles: self.config.allowed_roles,
308 });
309 mz_server_core::serve(ServeConfig {
310 conns: self.connection_stream,
311 server: sql_server,
312 dyncfg: None,
315 })
316 });
317 self.handle
318 }
319}
320
321impl Listener<HttpListenerConfig> {
322 #[instrument(name = "environmentd::serve_http")]
323 pub async fn serve_http(self, config: HttpConfig) -> ListenerHandle {
324 let task_name = format!("{}_http_server", config.source);
325 task::spawn(|| task_name, {
326 let http_server = HttpServer::new(config);
327 mz_server_core::serve(ServeConfig {
328 conns: self.connection_stream,
329 server: http_server,
330 dyncfg: None,
333 })
334 });
335 self.handle
336 }
337}
338
339static LISTENER_NAMES: LazyLock<Mutex<BTreeSet<&'static str>>> =
342 LazyLock::new(|| Mutex::new(BTreeSet::new()));
343
344fn leak_listener_name(name: &str) -> &'static str {
353 let mut names = LISTENER_NAMES.lock().expect("lock poisoned");
354 if let Some(name) = names.get(name) {
355 return name;
356 }
357 let name: &'static str = Box::leak(name.to_owned().into_boxed_str());
358 names.insert(name);
359 name
360}
361
362pub struct Listeners {
363 pub http: BTreeMap<String, Listener<HttpListenerConfig>>,
364 pub sql: BTreeMap<String, Listener<SqlListenerConfig>>,
365}
366
367impl Listeners {
368 pub async fn bind(config: ListenersConfig) -> Result<Self, io::Error> {
369 let mut sql = BTreeMap::new();
370 for (name, config) in config.sql {
371 sql.insert(name, Listener::bind(config).await?);
372 }
373
374 let mut http = BTreeMap::new();
375 for (name, config) in config.http {
376 http.insert(name, Listener::bind(config).await?);
377 }
378
379 Ok(Listeners { http, sql })
380 }
381
382 #[instrument(name = "environmentd::serve")]
386 pub async fn serve(self, config: Config) -> Result<Server, AdapterError> {
387 let serve_start = Instant::now();
388 info!("startup: envd serve: beginning");
389 info!("startup: envd serve: preamble beginning");
390
391 let tls_reloading_context = match config.tls {
393 Some(tls_config) => Some(tls_config.reloading_context(config.tls_reload_certs)?),
394 None => None,
395 };
396
397 let active_connection_counter = ConnectionCounter::default();
398 let (deployment_state, deployment_state_handle) = DeploymentState::new();
399
400 let webhook_concurrency_limit = WebhookConcurrencyLimiter::default();
409 let internal_route_config = Arc::new(InternalRouteConfig {
410 deployment_state_handle,
411 internal_console_redirect_url: config.internal_console_redirect_url,
412 });
413
414 let (authenticator_oidc_tx, authenticator_oidc_rx) = oneshot::channel();
415 let authenticator_oidc_rx = authenticator_oidc_rx.shared();
416 let (adapter_client_tx, adapter_client_rx) = oneshot::channel();
417 let adapter_client_rx = adapter_client_rx.shared();
418
419 let metrics_registry = config.metrics_registry.clone();
420 let metrics = http::Metrics::register_into(&metrics_registry, "mz_http");
421 let mcp_metrics = http::mcp_metrics::McpMetrics::register_into(&metrics_registry);
422 let oauth_metadata_metrics =
423 http::oauth_metadata::OauthMetadataMetrics::register_into(&metrics_registry);
424 let mut http_listener_handles = BTreeMap::new();
425 for (name, listener) in self.http {
426 let authenticator_kind = listener.config.authenticator_kind();
427 let source = leak_listener_name(&name);
428 let tls = if listener.config.enable_tls() {
429 tls_reloading_context.clone()
430 } else {
431 None
432 };
433 let http_config = HttpConfig {
434 adapter_client_rx: adapter_client_rx.clone(),
435 active_connection_counter: active_connection_counter.clone(),
436 helm_chart_version: config.helm_chart_version.clone(),
437 http_host_name: config.http_host_name.clone(),
438 frontegg_oauth_issuer_url: config.frontegg_oauth_issuer_url.clone(),
439 source,
440 tls,
441 authenticator_kind,
442 frontegg: config.frontegg.clone(),
443 oidc_rx: authenticator_oidc_rx.clone(),
444 allowed_origin: config.cors_allowed_origin.clone(),
445 allowed_origin_list: config.cors_allowed_origin_list.clone(),
446 concurrent_webhook_req: webhook_concurrency_limit.semaphore(),
447 dyncfgs: Arc::clone(&config.system_dyncfgs),
448 metrics: metrics.clone(),
449 metrics_registry: metrics_registry.clone(),
450 mcp_metrics: mcp_metrics.clone(),
451 oauth_metadata_metrics: oauth_metadata_metrics.clone(),
452 internal_route_config: Arc::clone(&internal_route_config),
453 routes_enabled: listener.config.routes,
454 replica_http_locator: Arc::clone(&config.controller.replica_http_locator),
455 };
456 http_listener_handles.insert(name.clone(), listener.serve_http(http_config).await);
457 }
458
459 info!(
460 "startup: envd serve: preamble complete in {:?}",
461 serve_start.elapsed()
462 );
463
464 let catalog_init_start = Instant::now();
465 info!("startup: envd serve: catalog init beginning");
466
467 let boot_ts = (config.now)().into();
469
470 let persist_client = config
471 .catalog_config
472 .persist_clients
473 .open(config.controller.persist_location.clone())
474 .await
475 .context("opening persist client")?;
476 let mut openable_adapter_storage = mz_catalog::durable::persist_backed_catalog_state(
477 persist_client.clone(),
478 config.environment_id.organization_id(),
479 BUILD_INFO.semver_version(),
480 Some(config.controller.deploy_generation),
481 Arc::clone(&config.catalog_config.metrics),
482 )
483 .await?;
484
485 info!(
486 "startup: envd serve: catalog init complete in {:?}",
487 catalog_init_start.elapsed()
488 );
489
490 let system_param_sync_start = Instant::now();
491 info!("startup: envd serve: system parameter sync beginning");
492 let system_parameter_sync_config =
494 match (config.launchdarkly_sdk_key, config.config_sync_file_path) {
495 (None, None) => None,
496 (None, Some(f)) => {
497 info!("Using config file path {:?}", f);
498 Some(SystemParameterSyncConfig::new(
499 config.environment_id.clone(),
500 &BUILD_INFO,
501 &config.metrics_registry,
502 config.launchdarkly_key_map,
503 SystemParameterSyncClientConfig::File { path: f },
504 ))
505 }
506 (Some(key), None) => Some(SystemParameterSyncConfig::new(
507 config.environment_id.clone(),
508 &BUILD_INFO,
509 &config.metrics_registry,
510 config.launchdarkly_key_map,
511 SystemParameterSyncClientConfig::LaunchDarkly {
512 sdk_key: key,
513 base_uri: config.launchdarkly_base_uri,
514 now_fn: config.now.clone(),
515 },
516 )),
517
518 (Some(_), Some(_)) => {
519 panic!("Cannot configure both file and Launchdarkly based config syncing")
520 }
521 };
522
523 let RemoteSystemParameters {
524 params: remote_system_parameters,
525 frontend: boot_frontend,
526 } = load_remote_system_parameters(
527 &mut openable_adapter_storage,
528 system_parameter_sync_config.clone(),
529 config.config_sync_timeout,
530 )
531 .await?;
532 info!(
533 "startup: envd serve: system parameter sync complete in {:?}",
534 system_param_sync_start.elapsed()
535 );
536
537 let preflight_checks_start = Instant::now();
538 info!("startup: envd serve: preflight checks beginning");
539
540 let with_0dt_deployment_max_wait = {
542 let cli_default = config
543 .system_parameter_defaults
544 .get(WITH_0DT_DEPLOYMENT_MAX_WAIT.name())
545 .map(|x| {
546 Duration::parse(VarInput::Flat(x)).map_err(|err| {
547 anyhow!(
548 "failed to parse default for {}: {:?}",
549 WITH_0DT_DEPLOYMENT_MAX_WAIT.name(),
550 err
551 )
552 })
553 })
554 .transpose()?;
555 let compiled_default = WITH_0DT_DEPLOYMENT_MAX_WAIT.default().clone();
556 let ld = get_ld_value(
557 WITH_0DT_DEPLOYMENT_MAX_WAIT.name(),
558 &remote_system_parameters,
559 |x| {
560 Duration::parse(VarInput::Flat(x)).map_err(|err| {
561 format!(
562 "failed to parse LD value {} for {}: {:?}",
563 x,
564 WITH_0DT_DEPLOYMENT_MAX_WAIT.name(),
565 err
566 )
567 })
568 },
569 )?;
570 let catalog = openable_adapter_storage
571 .get_0dt_deployment_max_wait()
572 .await?;
573 let computed = ld.or(catalog).or(cli_default).unwrap_or(compiled_default);
574 info!(
575 ?computed,
576 ?ld,
577 ?catalog,
578 ?cli_default,
579 ?compiled_default,
580 "determined value for {} system parameter",
581 WITH_0DT_DEPLOYMENT_MAX_WAIT.name()
582 );
583 computed
584 };
585 let with_0dt_deployment_ddl_check_interval = {
587 let cli_default = config
588 .system_parameter_defaults
589 .get(WITH_0DT_DEPLOYMENT_DDL_CHECK_INTERVAL.name())
590 .map(|x| {
591 Duration::parse(VarInput::Flat(x)).map_err(|err| {
592 anyhow!(
593 "failed to parse default for {}: {:?}",
594 WITH_0DT_DEPLOYMENT_DDL_CHECK_INTERVAL.name(),
595 err
596 )
597 })
598 })
599 .transpose()?;
600 let compiled_default = WITH_0DT_DEPLOYMENT_DDL_CHECK_INTERVAL.default().clone();
601 let ld = get_ld_value(
602 WITH_0DT_DEPLOYMENT_DDL_CHECK_INTERVAL.name(),
603 &remote_system_parameters,
604 |x| {
605 Duration::parse(VarInput::Flat(x)).map_err(|err| {
606 format!(
607 "failed to parse LD value {} for {}: {:?}",
608 x,
609 WITH_0DT_DEPLOYMENT_DDL_CHECK_INTERVAL.name(),
610 err
611 )
612 })
613 },
614 )?;
615 let catalog = openable_adapter_storage
616 .get_0dt_deployment_ddl_check_interval()
617 .await?;
618 let computed = ld.or(catalog).or(cli_default).unwrap_or(compiled_default);
619 info!(
620 ?computed,
621 ?ld,
622 ?catalog,
623 ?cli_default,
624 ?compiled_default,
625 "determined value for {} system parameter",
626 WITH_0DT_DEPLOYMENT_DDL_CHECK_INTERVAL.name()
627 );
628 computed
629 };
630
631 let enable_0dt_deployment_panic_after_timeout = {
634 let cli_default = config
635 .system_parameter_defaults
636 .get(ENABLE_0DT_DEPLOYMENT_PANIC_AFTER_TIMEOUT.name())
637 .map(|x| {
638 strconv::parse_bool(x).map_err(|err| {
639 anyhow!(
640 "failed to parse default for {}: {}",
641 ENABLE_0DT_DEPLOYMENT_PANIC_AFTER_TIMEOUT.name(),
642 err
643 )
644 })
645 })
646 .transpose()?;
647 let compiled_default = ENABLE_0DT_DEPLOYMENT_PANIC_AFTER_TIMEOUT.default().clone();
648 let ld = get_ld_value(
649 "enable_0dt_deployment_panic_after_timeout",
650 &remote_system_parameters,
651 |x| strconv::parse_bool(x).map_err(|x| x.to_string()),
652 )?;
653 let catalog = openable_adapter_storage
654 .get_enable_0dt_deployment_panic_after_timeout()
655 .await?;
656 let computed = ld.or(catalog).or(cli_default).unwrap_or(compiled_default);
657 info!(
658 %computed,
659 ?ld,
660 ?catalog,
661 ?cli_default,
662 ?compiled_default,
663 "determined value for enable_0dt_deployment_panic_after_timeout system parameter",
664 );
665 computed
666 };
667
668 let read_only = preflight::preflight_0dt(
672 openable_adapter_storage.as_mut(),
673 config.controller.deploy_generation,
674 )
675 .await?;
676
677 let bootstrap_args = BootstrapArgs {
678 default_cluster_replica_size: config.bootstrap_default_cluster_replica_size.clone(),
679 default_cluster_replication_factor: config.bootstrap_default_cluster_replication_factor,
680 bootstrap_role: config.bootstrap_role,
681 cluster_replica_size_map: config.cluster_replica_sizes.clone(),
682 };
683
684 let (caught_up_trigger, bootstrapped) = if read_only {
685 let (caught_up_trigger, caught_up_receiver) = mz_ore::channel::trigger::channel();
686 let (bootstrapped, bootstrapped_receiver) = tokio::sync::oneshot::channel();
687 let catchup_config = CatchupConfig {
688 boot_ts,
689 environment_id: config.environment_id.clone(),
690 persist_client,
691 deploy_generation: config.controller.deploy_generation,
692 deployment_state: deployment_state.clone(),
693 catalog_metrics: Arc::clone(&config.catalog_config.metrics),
694 caught_up_max_wait: with_0dt_deployment_max_wait,
695 panic_after_timeout: enable_0dt_deployment_panic_after_timeout,
696 bootstrap_args: bootstrap_args.clone(),
697 ddl_check_interval: with_0dt_deployment_ddl_check_interval,
698 };
699 preflight::spawn_catchup(catchup_config, caught_up_receiver, bootstrapped_receiver);
700 (Some(caught_up_trigger), Some(bootstrapped))
701 } else {
702 (None, None)
703 };
704
705 info!(
706 "startup: envd serve: preflight checks complete in {:?}",
707 preflight_checks_start.elapsed()
708 );
709
710 let catalog_open_start = Instant::now();
711 info!("startup: envd serve: durable catalog open beginning");
712
713 let mut adapter_storage = if read_only {
715 let adapter_storage = openable_adapter_storage
718 .open_savepoint(boot_ts, &bootstrap_args)
719 .await?;
720 adapter_storage
725 } else {
726 let adapter_storage = openable_adapter_storage
727 .open(boot_ts, &bootstrap_args)
728 .await?;
729
730 deployment_state.set_is_leader();
734
735 adapter_storage
736 };
737
738 let bootstrapped = match bootstrapped {
739 Some(tx) => Some((tx, preflight::get_user_ids(adapter_storage.as_mut()).await?)),
740 None => None,
741 };
742
743 if !read_only {
745 config.controller.persist_clients.cfg().enable_compaction();
746 }
747
748 info!(
749 "startup: envd serve: durable catalog open complete in {:?}",
750 catalog_open_start.elapsed()
751 );
752
753 let coord_init_start = Instant::now();
754 info!("startup: envd serve: coordinator init beginning");
755
756 if !config
757 .cluster_replica_sizes
758 .0
759 .contains_key(&config.bootstrap_default_cluster_replica_size)
760 {
761 return Err(anyhow!("bootstrap default cluster replica size is unknown").into());
762 }
763 let envd_epoch = adapter_storage.epoch();
764
765 let storage_usage_client = StorageUsageClient::open(
767 config
768 .controller
769 .persist_clients
770 .open(config.controller.persist_location.clone())
771 .await
772 .context("opening storage usage client")?,
773 );
774
775 let license_key = config.license_key.clone();
777 let segment_client = config.segment_api_key.map(|api_key| {
778 mz_segment::Client::new(mz_segment::Config {
779 api_key,
780 client_side: config.segment_client_side,
781 })
782 });
783 let connection_limiter = active_connection_counter.clone();
784 let connection_limit_callback = Box::new(move |limit, superuser_reserved| {
785 connection_limiter.update_limit(limit);
786 connection_limiter.update_superuser_reserved(superuser_reserved);
787 });
788
789 let (adapter_handle, adapter_client) = mz_adapter::serve(mz_adapter::Config {
790 connection_context: config.controller.connection_context.clone(),
791 connection_limit_callback,
792 controller_config: config.controller,
793 controller_envd_epoch: envd_epoch,
794 storage: adapter_storage,
795 timestamp_oracle_url: config.timestamp_oracle_url,
796 unsafe_mode: config.unsafe_mode,
797 all_features: config.all_features,
798 build_info: &BUILD_INFO,
799 environment_id: config.environment_id.clone(),
800 metrics_registry: config.metrics_registry.clone(),
801 now: config.now,
802 secrets_controller: config.secrets_controller,
803 cloud_resource_controller: config.cloud_resource_controller,
804 cluster_replica_sizes: config.cluster_replica_sizes,
805 builtin_system_cluster_config: config.bootstrap_builtin_system_cluster_config,
806 builtin_catalog_server_cluster_config: config
807 .bootstrap_builtin_catalog_server_cluster_config,
808 builtin_probe_cluster_config: config.bootstrap_builtin_probe_cluster_config,
809 builtin_support_cluster_config: config.bootstrap_builtin_support_cluster_config,
810 builtin_analytics_cluster_config: config.bootstrap_builtin_analytics_cluster_config,
811 availability_zones: config.availability_zones,
812 system_parameter_defaults: config.system_parameter_defaults,
813 storage_usage_client,
814 storage_usage_collection_interval: config.storage_usage_collection_interval,
815 storage_usage_retention_period: config.storage_usage_retention_period,
816 segment_client: segment_client.clone(),
817 egress_addresses: config.egress_addresses,
818 remote_system_parameters,
819 aws_account_id: config.aws_account_id,
820 aws_privatelink_availability_zones: config.aws_privatelink_availability_zones,
821 webhook_concurrency_limit: webhook_concurrency_limit.clone(),
822 http_host_name: config.http_host_name,
823 tracing_handle: config.tracing_handle,
824 read_only_controllers: read_only,
825 caught_up_trigger,
826 helm_chart_version: config.helm_chart_version.clone(),
827 license_key: config.license_key,
828 external_login_password_mz_system: config.external_login_password_mz_system,
829 force_builtin_schema_migration: config.force_builtin_schema_migration,
830 })
831 .instrument(info_span!("adapter::serve"))
832 .await?;
833
834 if let Some((tx, initial_ids)) = bootstrapped {
835 let _ = tx.send(initial_ids);
837 }
838
839 let oidc = GenericOidcAuthenticator::new(adapter_client.clone());
841
842 info!(
843 "startup: envd serve: coordinator init complete in {:?}",
844 coord_init_start.elapsed()
845 );
846
847 let serve_postamble_start = Instant::now();
848 info!("startup: envd serve: postamble beginning");
849
850 authenticator_oidc_tx
852 .send(oidc.clone())
853 .expect("rx known to be live");
854 adapter_client_tx
855 .send(adapter_client.clone())
856 .expect("internal HTTP server should not drop first");
857
858 let metrics = mz_pgwire::MetricsConfig::register_into(&config.metrics_registry);
859
860 let mut sql_listener_handles = BTreeMap::new();
862 for (name, listener) in self.sql {
863 sql_listener_handles.insert(
864 name.clone(),
865 listener
866 .serve_sql(
867 name,
868 active_connection_counter.clone(),
869 tls_reloading_context.clone(),
870 config.frontegg.clone(),
871 adapter_client.clone(),
872 oidc.clone(),
873 metrics.clone(),
874 config.helm_chart_version.clone(),
875 )
876 .await,
877 );
878 }
879
880 if let Some(segment_client) = segment_client {
882 telemetry::start_reporting(telemetry::Config {
883 segment_client,
884 adapter_client: adapter_client.clone(),
885 environment_id: config.environment_id,
886 license_key: license_key.clone(),
887 helm_chart_version: config.helm_chart_version.clone(),
888 report_interval: Duration::from_secs(3600),
889 });
890 } else if config.test_only_dummy_segment_client {
891 tracing::debug!("starting telemetry reporting with a dummy segment client");
897 let segment_client = mz_segment::Client::new_dummy_client();
898 telemetry::start_reporting(telemetry::Config {
899 segment_client,
900 adapter_client: adapter_client.clone(),
901 environment_id: config.environment_id,
902 license_key: license_key.clone(),
903 helm_chart_version: config.helm_chart_version.clone(),
904 report_interval: Duration::from_secs(180),
905 });
906 }
907
908 if let Some(system_parameter_sync_config) = system_parameter_sync_config {
911 task::spawn(
912 || "system_parameter_sync",
913 AssertUnwindSafe(system_parameter_sync(
914 system_parameter_sync_config,
915 boot_frontend,
916 adapter_client.clone(),
917 config.config_sync_loop_interval,
918 ))
919 .ore_catch_unwind(),
920 );
921 }
922
923 info!(
924 "startup: envd serve: postamble complete in {:?}",
925 serve_postamble_start.elapsed()
926 );
927 info!(
928 "startup: envd serve: complete in {:?}",
929 serve_start.elapsed()
930 );
931
932 Ok(Server {
933 sql_listener_handles,
934 http_listener_handles,
935 #[cfg(feature = "test")]
936 adapter_client,
937 _adapter_handle: adapter_handle,
938 })
939 }
940}
941
942fn get_ld_value<V>(
943 name: &str,
944 remote_system_parameters: &Option<BTreeMap<String, String>>,
945 parse: impl Fn(&str) -> Result<V, String>,
946) -> Result<Option<V>, anyhow::Error> {
947 remote_system_parameters
948 .as_ref()
949 .and_then(|params| params.get(name))
950 .map(|x| {
951 parse(x).map_err(|err| anyhow!("failed to parse remote value for {}: {}", name, err))
952 })
953 .transpose()
954}
955
956pub struct Server {
958 pub sql_listener_handles: BTreeMap<String, ListenerHandle>,
960 pub http_listener_handles: BTreeMap<String, ListenerHandle>,
961 #[cfg(feature = "test")]
962 adapter_client: AdapterClient,
963 _adapter_handle: mz_adapter::Handle,
964}
965
966impl Server {
967 #[cfg(feature = "test")]
969 pub fn adapter_client(&self) -> &AdapterClient {
970 &self.adapter_client
971 }
972}