@@ -11,7 +11,6 @@ use crate::blueprint_editor::EditedSled;
1111use crate :: blueprint_editor:: ExternalNetworkingChoice ;
1212use crate :: blueprint_editor:: ExternalNetworkingError ;
1313use crate :: blueprint_editor:: ExternalSnatNetworkingChoice ;
14- use crate :: blueprint_editor:: NoAvailableDnsSubnets ;
1514use crate :: blueprint_editor:: SledEditError ;
1615use crate :: blueprint_editor:: SledEditor ;
1716use crate :: mgs_updates:: PendingHostPhase2Changes ;
@@ -65,6 +64,7 @@ use nexus_types::inventory::Collection;
6564use omicron_common:: address:: CLICKHOUSE_HTTP_PORT ;
6665use omicron_common:: address:: DNS_HTTP_PORT ;
6766use omicron_common:: address:: DNS_PORT ;
67+ use omicron_common:: address:: DnsSubnet ;
6868use omicron_common:: address:: NTP_PORT ;
6969use omicron_common:: address:: ReservedRackSubnet ;
7070use omicron_common:: api:: external:: Generation ;
@@ -137,8 +137,10 @@ pub enum Error {
137137 } ,
138138 #[ error( "error constructing resource allocator" ) ]
139139 AllocatorInput ( #[ from] BlueprintResourceAllocatorInputError ) ,
140- #[ error( "error allocating internal DNS subnet" ) ]
141- AllocateInternalDnsSubnet ( #[ from] NoAvailableDnsSubnets ) ,
140+ #[ error( "no commissioned sleds - rack subnet is unknown" ) ]
141+ RackSubnetUnknownNoSleds ,
142+ #[ error( "no reserved subnets available for internal DNS" ) ]
143+ NoAvailableDnsSubnets ,
142144 #[ error( "error allocating external networking resources" ) ]
143145 AllocateExternalNetworking ( #[ from] ExternalNetworkingError ) ,
144146 #[ error( "zone is already up-to-date and should not be updated" ) ]
@@ -693,6 +695,40 @@ impl<'a> BlueprintBuilder<'a> {
693695 self . new_blueprint_id
694696 }
695697
698+ pub fn available_internal_dns_subnets (
699+ & self ,
700+ ) -> Result < impl Iterator < Item = DnsSubnet > , Error > {
701+ // TODO-multirack We need the rack subnet to know what the reserved
702+ // internal DNS subnets are. Pick any sled; this isn't right in
703+ // multirack (either DNS will be on a wider subnet or we need to pick a
704+ // particular rack subnet here?).
705+ let any_sled_subnet = self
706+ . input
707+ . all_sled_resources ( SledFilter :: Commissioned )
708+ . map ( |( _sled_id, resources) | resources. subnet )
709+ . next ( )
710+ . ok_or ( Error :: RackSubnetUnknownNoSleds ) ?;
711+ let rack_subnet = ReservedRackSubnet :: from_subnet ( any_sled_subnet) ;
712+
713+ // Compute the "in use" subnets; this includes all in-service internal
714+ // DNS zones _and_ any "expunged but not yet confirmed to be gone"
715+ // zones, so we use the somewhat unusual `could_be_running` filter
716+ // instead of the more typical `is_in_service`.
717+ let internal_dns_subnets_in_use = self
718+ . current_zones ( BlueprintZoneDisposition :: could_be_running)
719+ . filter_map ( |( _sled_id, zone) | match & zone. zone_type {
720+ BlueprintZoneType :: InternalDns ( internal_dns) => {
721+ Some ( DnsSubnet :: from_addr ( * internal_dns. dns_address . ip ( ) ) )
722+ }
723+ _ => None ,
724+ } )
725+ . collect :: < BTreeSet < _ > > ( ) ;
726+
727+ Ok ( rack_subnet. get_dns_subnets ( ) . into_iter ( ) . filter ( move |subnet| {
728+ !internal_dns_subnets_in_use. contains ( & subnet)
729+ } ) )
730+ }
731+
696732 pub fn planning_input ( & self ) -> & PlanningInput {
697733 & self . input
698734 }
@@ -1381,12 +1417,9 @@ impl<'a> BlueprintBuilder<'a> {
13811417 & mut self ,
13821418 sled_id : SledUuid ,
13831419 image_source : BlueprintZoneImageSource ,
1420+ dns_subnet : DnsSubnet ,
13841421 ) -> Result < ( ) , Error > {
13851422 let gz_address_index = self . next_internal_dns_gz_address_index ( sled_id) ;
1386- let sled_subnet = self . sled_resources ( sled_id) ?. subnet ;
1387- let rack_subnet = ReservedRackSubnet :: from_subnet ( sled_subnet) ;
1388- let dns_subnet =
1389- self . resource_allocator ( ) ?. next_internal_dns_subnet ( rack_subnet) ?;
13901423 let address = dns_subnet. dns_address ( ) ;
13911424 let zpool = self . sled_select_zpool ( sled_id, ZoneKind :: InternalDns ) ?;
13921425 let zone_type =
0 commit comments