Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 15 additions & 25 deletions dev-tools/omdb/src/bin/omdb/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ use clap::Parser;
use clap::Subcommand;
use futures::StreamExt;
use internal_dns_types::names::ServiceName;
use omicron_common::address::Ipv6Subnet;
use std::net::SocketAddr;
use std::net::SocketAddrV6;
use tokio::net::TcpSocket;
Expand Down Expand Up @@ -249,34 +248,25 @@ impl Omdb {
})
}
None => {
// In principle, we should look at /etc/resolv.conf to find the
// DNS servers. In practice, this usually isn't populated
// today. See oxidecomputer/omicron#2122.
//
// However, the address selected below should work for most
// existing Omicron deployments today. That's because while the
// base subnet is in principle configurable in config-rss.toml,
// it's very uncommon to change it from the default value used
// here.
//
// Yet another option would be to find a local IP address that
// looks like it's probably on the underlay network and use that
// to find the subnet to use. But again, this is unlikely to be
// wrong and it's easy to override.
let subnet =
Ipv6Subnet::new("fd00:1122:3344:0100::".parse().unwrap());
eprintln!("note: using DNS server for subnet {}", subnet.net());
// We now populate the internal DNS servers in /etc/resolv.conf
// within the switch zone (the primary location for running
// omdb). Notify the user that we're going to attempt DNS
// resolution via the default system path. This will be wrong if
// the rack is not set up yet (although omdb is useless at that
// point anyway) or if we're running somewhere where
// /etc/resolv.conf does not point to our internal DNS servers
// (a non-switch zone without DNS configured, a development
// system, etc.).
eprintln!(
"note: using DNS from system config \
(typically /etc/resolv.conf)"
);
eprintln!(
"note: (if this is not right, use --dns-server \
to specify an alternate DNS server)",
);
internal_dns_resolver::Resolver::new_from_subnet(log, subnet)
.with_context(|| {
format!(
"creating DNS resolver for subnet {}",
subnet.net()
)
})
internal_dns_resolver::Resolver::new_from_system_conf(log)
.context("creating DNS resolver from system config")
}
}
}
Expand Down
13 changes: 12 additions & 1 deletion illumos-utils/src/smf_helper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

use crate::running_zone::RunningZone;
use crate::zone::SVCADM;
use crate::zone::SVCCFG;

#[derive(thiserror::Error, Debug)]
Expand All @@ -16,7 +17,7 @@ pub enum Error {
}

pub trait Service {
fn service_name(&self) -> String;
fn service_name(&self) -> &str;
fn smf_name(&self) -> String;
}

Expand Down Expand Up @@ -245,4 +246,14 @@ impl<'t> SmfHelper<'t> {
})?;
Ok(())
}

pub fn enable(&self) -> Result<(), Error> {
self.running_zone
.run_cmd(&[SVCADM, "enable", &self.smf_name])
.map_err(|err| Error::ZoneCommand {
intent: format!("Enable SMF service {}", self.default_smf_name),
err,
})?;
Ok(())
}
}
83 changes: 67 additions & 16 deletions sled-agent/src/services.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ use illumos_utils::running_zone::{
EnsureAddressError, InstalledZone, RunCommandError, RunningZone,
ZoneBuilderFactory,
};
use illumos_utils::smf_helper::Service as _;
use illumos_utils::smf_helper::SmfHelper;
use illumos_utils::zfs::ZONE_ZFS_RAMDISK_DATASET_MOUNTPOINT;
use illumos_utils::zone::AddressRequest;
Expand Down Expand Up @@ -471,7 +472,7 @@ enum SwitchService {
}

impl illumos_utils::smf_helper::Service for SwitchService {
fn service_name(&self) -> String {
fn service_name(&self) -> &str {
match self {
SwitchService::ManagementGatewayService => "mgs",
SwitchService::Wicketd { .. } => "wicketd",
Expand All @@ -484,13 +485,31 @@ impl illumos_utils::smf_helper::Service for SwitchService {
SwitchService::Mgd => "mgd",
SwitchService::SpSim => "sp-sim",
}
.to_owned()
}
fn smf_name(&self) -> String {
format!("svc:/oxide/{}", self.service_name())
}
}

/// Describes SMF services related to DNS.
#[derive(Debug, Clone, Copy)]
enum DnsService {
Client,
Install,
}

impl illumos_utils::smf_helper::Service for DnsService {
fn service_name(&self) -> &str {
match self {
Self::Client => "network/dns/client",
Self::Install => "network/dns/install",
}
}
fn smf_name(&self) -> String {
format!("svc:/{}", self.service_name())
}
}

/// Describes either an Omicron-managed zone or the switch zone, used for
/// functions that operate on either one or the other
enum ZoneArgs<'a> {
Expand Down Expand Up @@ -1246,7 +1265,7 @@ impl ServiceManager {
needed
}

async fn dns_install(
fn dns_install(
info: &SledAgentInfo,
ip_addrs: Option<Vec<IpAddr>>,
domain: Option<&str>,
Expand Down Expand Up @@ -1288,7 +1307,7 @@ impl ServiceManager {
None => (),
}

Ok(ServiceBuilder::new("network/dns/install")
Ok(ServiceBuilder::new(DnsService::Install.service_name())
.add_property_group(dns_config_builder)
// We do need to enable the default instance of the
// dns/install service. It's enough to just mention it
Expand Down Expand Up @@ -1519,11 +1538,11 @@ impl ServiceManager {
.add_instance(ServiceInstanceBuilder::new("default").disable());

let disabled_dns_client_service =
ServiceBuilder::new("network/dns/client")
ServiceBuilder::new(DnsService::Client.service_name())
.add_instance(ServiceInstanceBuilder::new("default").disable());

let enabled_dns_client_service =
ServiceBuilder::new("network/dns/client")
ServiceBuilder::new(DnsService::Client.service_name())
.add_instance(ServiceInstanceBuilder::new("default"));

let running_zone = match config {
Expand All @@ -1541,7 +1560,7 @@ impl ServiceManager {
&[*address.ip()],
)?;

let dns_service = Self::dns_install(info, None, None).await?;
let dns_service = Self::dns_install(info, None, None)?;

let config = PropertyGroupBuilder::new("config")
.add_property(
Expand Down Expand Up @@ -1626,7 +1645,7 @@ impl ServiceManager {
&[*address.ip()],
)?;

let dns_service = Self::dns_install(info, None, None).await?;
let dns_service = Self::dns_install(info, None, None)?;

let clickhouse_server_config =
PropertyGroupBuilder::new("config")
Expand Down Expand Up @@ -1711,7 +1730,7 @@ impl ServiceManager {
&[*address.ip()],
)?;

let dns_service = Self::dns_install(info, None, None).await?;
let dns_service = Self::dns_install(info, None, None)?;

let clickhouse_keeper_config =
PropertyGroupBuilder::new("config")
Expand Down Expand Up @@ -1802,7 +1821,7 @@ impl ServiceManager {
&[*address.ip()],
)?;

let dns_service = Self::dns_install(info, None, None).await?;
let dns_service = Self::dns_install(info, None, None)?;

// Configure the CockroachDB service.
let cockroachdb_config = PropertyGroupBuilder::new("config")
Expand Down Expand Up @@ -2085,8 +2104,7 @@ impl ServiceManager {
info,
Some(dns_servers.to_vec()),
domain.as_deref(),
)
.await?;
)?;

let mut chrony_config = PropertyGroupBuilder::new("config")
.add_property("allow", "astring", &rack_net)
Expand Down Expand Up @@ -2178,8 +2196,7 @@ impl ServiceManager {
.net()
.to_string();

let dns_install_service =
Self::dns_install(info, None, None).await?;
let dns_install_service = Self::dns_install(info, None, None)?;

let chrony_config = PropertyGroupBuilder::new("config")
.add_property("allow", "astring", &rack_net)
Expand Down Expand Up @@ -2510,7 +2527,7 @@ impl ServiceManager {
let SwitchZoneConfig { id, services, addresses, .. } = config;

let disabled_dns_client_service =
ServiceBuilder::new("network/dns/client")
ServiceBuilder::new(DnsService::Client.service_name())
.add_instance(ServiceInstanceBuilder::new("default").disable());

let info = self.inner.sled_info.get();
Expand Down Expand Up @@ -3128,7 +3145,7 @@ impl ServiceManager {
.add_property_group(switch_zone_setup_config),
);

let profile = ProfileBuilder::new("omicron")
let mut profile = ProfileBuilder::new("omicron")
.add_service(nw_setup_service)
.add_service(disabled_dns_client_service)
.add_service(mgs_service)
Expand All @@ -3141,9 +3158,17 @@ impl ServiceManager {
.add_service(mgd_service)
.add_service(mg_ddm_service)
.add_service(uplink_service);

// If we have the rack subnet, also set up /etc/resolv.conf.
if let Some(info) = info {
let dns_service = Self::dns_install(info, None, None)?;
profile = profile.add_service(dns_service);
}

profile.add_to_zone(&self.inner.log, &installed_zone).await.map_err(
|err| Error::io("Failed to setup Switch zone profile", err),
)?;

Ok(RunningZone::boot(installed_zone).await?)
}

Expand Down Expand Up @@ -3971,6 +3996,32 @@ impl ServiceManager {
}
}

// If we have our sled-agent info (which we should, if we're
// reconfiguring the switch zone!), we also need to set up
// `/etc/resolv.conf`. Do so by reconfiguring
// `network/dns/install` and enabling that service.
if let Some(info) = self.inner.sled_info.get() {
let smfh = SmfHelper::new(&zone, &DnsService::Install);
let nameservers = get_internal_dns_server_addresses(
info.underlay_address,
);
smfh.delpropvalue("install_props/nameserver", "*")?;
for address in &nameservers {
smfh.addpropvalue_type(
"install_props/nameserver",
&format!("{address}"),
"net_address",
)?;
}
smfh.refresh()?;
smfh.enable()?;
info!(
self.inner.log,
"enabled DNS install service with new nameservers";
"nameservers" => ?nameservers,
);
}

// We also need to ensure any uplinks are configured. Spawn a
// task that goes into an infinite retry loop until it succeeds.
if let Some(underlay_info) = request.underlay_info.clone() {
Expand Down
Loading