diff --git a/dev-tools/omicron-dev/src/main.rs b/dev-tools/omicron-dev/src/main.rs index 9fa5ac0fc05..58dbef377e4 100644 --- a/dev-tools/omicron-dev/src/main.rs +++ b/dev-tools/omicron-dev/src/main.rs @@ -48,9 +48,18 @@ enum OmicronDevCmd { #[derive(Clone, Debug, Args)] struct RunAllArgs { - /// Nexus external API listen port. Use `0` to request any available port. + /// Nexus external API listen port. Use `0` to request any available port. #[clap(long, action)] nexus_listen_port: Option, + /// CockroachDB listen port. Use `0` to request any available port. + #[clap(long)] + db_listen_port: Option, + /// Internal DNS listen port. Use `0` to request any available port. + #[clap(long)] + internal_dns_listen_port: Option, + /// Management gateway listen port. Use `0` to request any available port. + #[clap(long)] + mgs_listen_port: Option, /// Override the gateway server configuration file. #[clap(long, default_value = DEFAULT_SP_SIM_CONFIG)] gateway_config: Utf8PathBuf, @@ -90,7 +99,14 @@ impl RunAllArgs { println!("omicron-dev: setting up all services ... "); let cptestctx = nexus_test_utils::omicron_dev_setup_with_config::< omicron_nexus::Server, - >(&mut config, 0, self.gateway_config.clone()) + >( + &mut config, + 0, + self.gateway_config.clone(), + self.db_listen_port, + self.internal_dns_listen_port, + self.mgs_listen_port, + ) .await .context("error setting up services")?; diff --git a/nexus/db-queries/src/db/pub_test_utils/crdb.rs b/nexus/db-queries/src/db/pub_test_utils/crdb.rs index aa06f0681eb..d0fe4608f12 100644 --- a/nexus/db-queries/src/db/pub_test_utils/crdb.rs +++ b/nexus/db-queries/src/db/pub_test_utils/crdb.rs @@ -35,6 +35,7 @@ pub async fn test_setup_database(log: &Logger) -> dev::db::CockroachInstance { dev::test_setup_database( log, dev::StorageSource::CopyFromSeed { input_tar }, + None, ) .await } @@ -45,7 +46,7 @@ pub async fn test_setup_database(log: &Logger) -> dev::db::CockroachInstance { pub async fn test_setup_database_empty( log: &Logger, ) -> dev::db::CockroachInstance { - dev::test_setup_database(log, dev::StorageSource::DoNotPopulate).await + dev::test_setup_database(log, dev::StorageSource::DoNotPopulate, None).await } /// Wrapper around [`dev::test_setup_database`] which uses a seed tarball @@ -53,10 +54,12 @@ pub async fn test_setup_database_empty( pub async fn test_setup_database_from_seed( log: &Logger, input_tar: Utf8PathBuf, + listen_port: Option, ) -> dev::db::CockroachInstance { dev::test_setup_database( log, dev::StorageSource::CopyFromSeed { input_tar }, + listen_port, ) .await } diff --git a/nexus/test-utils/src/nexus_test.rs b/nexus/test-utils/src/nexus_test.rs index a57bf139a9b..c8b470548fb 100644 --- a/nexus/test-utils/src/nexus_test.rs +++ b/nexus/test-utils/src/nexus_test.rs @@ -361,8 +361,14 @@ pub async fn omicron_dev_setup_with_config( config: &mut NexusConfig, extra_sled_agents: u16, gateway_config_file: Utf8PathBuf, + db_listen_port: Option, + internal_dns_listen_port: Option, + mgs_listen_port: Option, ) -> Result> { - let starter = ControlPlaneStarter::::new("omicron-dev", config); + let mut starter = ControlPlaneStarter::::new("omicron-dev", config); + starter.db_listen_port(db_listen_port); + starter.internal_dns_listen_port(internal_dns_listen_port); + starter.mgs_listen_port(mgs_listen_port); let log = &starter.logctx.log; debug!(log, "Ensuring seed tarball exists"); diff --git a/nexus/test-utils/src/starter.rs b/nexus/test-utils/src/starter.rs index 696a40b8e88..9cc3d5cb0fa 100644 --- a/nexus/test-utils/src/starter.rs +++ b/nexus/test-utils/src/starter.rs @@ -166,6 +166,10 @@ pub struct ControlPlaneStarter<'a, N: NexusServer> { pub password: Option, pub simulated_upstairs: Arc, + + db_listen_port: Option, + internal_dns_listen_port: Option, + mgs_listen_port: Option, } type StepInitFn<'a, N> = Box< @@ -216,9 +220,24 @@ impl<'a, N: NexusServer> ControlPlaneStarter<'a, N> { simulated_upstairs: Arc::new(sim::SimulatedUpstairs::new( simulated_upstairs_log, )), + db_listen_port: None, + internal_dns_listen_port: None, + mgs_listen_port: None, } } + pub fn db_listen_port(&mut self, port: Option) { + self.db_listen_port = port; + } + + pub fn internal_dns_listen_port(&mut self, port: Option) { + self.internal_dns_listen_port = port; + } + + pub fn mgs_listen_port(&mut self, port: Option) { + self.mgs_listen_port = port; + } + pub async fn init_with_steps( &mut self, steps: Vec<(&str, StepInitFn<'a, N>)>, @@ -266,7 +285,12 @@ impl<'a, N: NexusServer> ControlPlaneStarter<'a, N> { } #[cfg(feature = "omicron-dev")] PopulateCrdb::FromSeed { input_tar } => { - crdb::test_setup_database_from_seed(log, input_tar).await + crdb::test_setup_database_from_seed( + log, + input_tar, + self.db_listen_port, + ) + .await } PopulateCrdb::Empty => crdb::test_setup_database_empty(log).await, }; @@ -1200,7 +1224,18 @@ impl<'a, N: NexusServer> ControlPlaneStarter<'a, N> { /// Set up an internal DNS server on the first sled agent pub async fn start_internal_dns(&mut self) { let log = self.logctx.log.new(o!("component" => "internal_dns_server")); - let dns = dns_server::TransientServer::new(&log).await.unwrap(); + let dns_addr = SocketAddrV6::new( + Ipv6Addr::LOCALHOST, + self.internal_dns_listen_port.unwrap_or(0), + 0, + 0, + ); + let dns = dns_server::TransientServer::new_with_address( + &log, + dns_addr.into(), + ) + .await + .unwrap(); let SocketAddr::V6(dns_address) = dns.dns_server.local_address() else { panic!("Unsupported IPv4 DNS address"); @@ -1621,7 +1656,7 @@ pub(crate) async fn setup_with_config_impl( builder .start_gateway( SwitchLocation::Switch0, - None, + builder.mgs_listen_port, mgs_config, ) .boxed() @@ -1665,7 +1700,7 @@ pub(crate) async fn setup_with_config_impl( builder .start_gateway( SwitchLocation::Switch1, - None, + builder.mgs_listen_port, gateway_config_file, ) .boxed() diff --git a/test-utils/src/dev/mod.rs b/test-utils/src/dev/mod.rs index 5a37ac2549e..ec6d9a23a9d 100644 --- a/test-utils/src/dev/mod.rs +++ b/test-utils/src/dev/mod.rs @@ -62,9 +62,10 @@ pub enum StorageSource { pub async fn test_setup_database( log: &Logger, source: StorageSource, + listen_port: Option, ) -> db::CockroachInstance { usdt::register_probes().expect("Failed to register USDT DTrace probes"); - setup_database(log, source).await.unwrap() + setup_database(log, source, listen_port).await.unwrap() } // TODO: switch to anyhow entirely -- this function is currently a mishmash of @@ -72,8 +73,10 @@ pub async fn test_setup_database( async fn setup_database( log: &Logger, storage_source: StorageSource, + listen_port: Option, ) -> Result { let builder = db::CockroachStarterBuilder::new(); + let builder = builder.listen_port(listen_port.unwrap_or(0)); let builder = match &storage_source { StorageSource::DoNotPopulate | StorageSource::CopyFromSeed { .. } => { builder diff --git a/test-utils/src/dev/seed.rs b/test-utils/src/dev/seed.rs index 5d5ea5beb44..6eca6daa8b3 100644 --- a/test-utils/src/dev/seed.rs +++ b/test-utils/src/dev/seed.rs @@ -173,6 +173,7 @@ pub async fn test_setup_database_seed( super::StorageSource::PopulateLatest { output_dir: tmp_seed_dir.path().to_owned(), }, + None, ) .await .context("failed to setup database")?;