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