Skip to content

Commit 2c30183

Browse files
committed
spread stuff across U.2 zpools too
1 parent 9c7bbf7 commit 2c30183

File tree

1 file changed

+74
-29
lines changed

1 file changed

+74
-29
lines changed

sled-agent/src/rack_setup/plan/service.rs

Lines changed: 74 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
use crate::bootstrap::params::StartSledAgentRequest;
88
use crate::ledger::{Ledger, Ledgerable};
99
use crate::params::{
10-
DatasetRequest, ServiceType, ServiceZoneRequest, ServiceZoneService,
11-
ZoneType,
10+
DatasetKind, DatasetRequest, ServiceType, ServiceZoneRequest,
11+
ServiceZoneService, ZoneType,
1212
};
1313
use crate::rack_setup::config::SetupServiceConfig as Config;
1414
use crate::storage::dataset::DatasetName;
@@ -89,6 +89,9 @@ pub enum PlanError {
8989

9090
#[error("Failed to construct an HTTP client: {0}")]
9191
HttpClient(reqwest::Error),
92+
93+
#[error("Ran out of sleds / U2 storage pools")]
94+
NotEnoughSleds,
9295
}
9396

9497
#[derive(Clone, Debug, Default, Deserialize, Serialize, PartialEq)]
@@ -250,15 +253,13 @@ impl Plan {
250253
.await?;
251254
let is_scrimlet =
252255
Self::is_sled_scrimlet(log, sled_address).await?;
253-
Ok(SledInfo {
254-
sled_id: sled_request.id,
256+
Ok(SledInfo::new(
257+
sled_request.id,
255258
subnet,
256259
sled_address,
257260
u2_zpools,
258261
is_scrimlet,
259-
addr_alloc: AddressBumpAllocator::new(subnet),
260-
request: Default::default(),
261-
})
262+
))
262263
},
263264
))
264265
.await;
@@ -316,10 +317,8 @@ impl Plan {
316317
DNS_HTTP_PORT,
317318
)
318319
.unwrap();
319-
let dataset_name = DatasetName::new(
320-
sled.u2_zpools[0].clone(),
321-
crate::params::DatasetKind::InternalDns,
322-
);
320+
let dataset_name =
321+
sled.alloc_from_u2_zpool(DatasetKind::InternalDns)?;
323322

324323
sled.request.services.push(ServiceZoneRequest {
325324
id,
@@ -350,17 +349,13 @@ impl Plan {
350349
dns_builder
351350
.service_backend_zone(ServiceName::Cockroach, &zone, port)
352351
.unwrap();
352+
let dataset_name =
353+
sled.alloc_from_u2_zpool(DatasetKind::CockroachDb)?;
353354
sled.request.services.push(ServiceZoneRequest {
354355
id,
355356
zone_type: ZoneType::CockroachDb,
356357
addresses: vec![ip],
357-
dataset: Some(DatasetRequest {
358-
id,
359-
name: DatasetName::new(
360-
sled.u2_zpools[0].clone(),
361-
crate::params::DatasetKind::CockroachDb,
362-
),
363-
}),
358+
dataset: Some(DatasetRequest { id, name: dataset_name }),
364359
gz_addresses: vec![],
365360
services: vec![ServiceZoneService {
366361
id,
@@ -434,9 +429,8 @@ impl Plan {
434429
svc_port_builder.next_dns(id, &mut services_ip_pool)?;
435430
let dns_port = omicron_common::address::DNS_PORT;
436431
let dns_address = SocketAddr::new(external_ip, dns_port);
437-
let dataset_kind = crate::params::DatasetKind::ExternalDns;
438-
let dataset_name =
439-
DatasetName::new(sled.u2_zpools[0].clone(), dataset_kind);
432+
let dataset_kind = DatasetKind::ExternalDns;
433+
let dataset_name = sled.alloc_from_u2_zpool(dataset_kind)?;
440434

441435
sled.request.services.push(ServiceZoneRequest {
442436
id,
@@ -499,17 +493,13 @@ impl Plan {
499493
dns_builder
500494
.service_backend_zone(ServiceName::Clickhouse, &zone, port)
501495
.unwrap();
496+
let dataset_name =
497+
sled.alloc_from_u2_zpool(DatasetKind::Clickhouse)?;
502498
sled.request.services.push(ServiceZoneRequest {
503499
id,
504500
zone_type: ZoneType::Clickhouse,
505501
addresses: vec![ip],
506-
dataset: Some(DatasetRequest {
507-
id,
508-
name: DatasetName::new(
509-
sled.u2_zpools[0].clone(),
510-
crate::params::DatasetKind::Clickhouse,
511-
),
512-
}),
502+
dataset: Some(DatasetRequest { id, name: dataset_name }),
513503
gz_addresses: vec![],
514504
services: vec![ServiceZoneService {
515505
id,
@@ -569,7 +559,7 @@ impl Plan {
569559
id,
570560
name: DatasetName::new(
571561
pool.clone(),
572-
crate::params::DatasetKind::Crucible,
562+
DatasetKind::Crucible,
573563
),
574564
}),
575565
gz_addresses: vec![],
@@ -685,6 +675,9 @@ struct SledInfo {
685675
sled_address: SocketAddrV6,
686676
/// the list of zpools on the Sled
687677
u2_zpools: Vec<ZpoolName>,
678+
/// spreads components across a Sled's zpools
679+
u2_zpool_allocators:
680+
HashMap<DatasetKind, Box<dyn Iterator<Item = usize> + Send + Sync>>,
688681
/// whether this Sled is a scrimlet
689682
is_scrimlet: bool,
690683
/// allocator for addresses in this Sled's subnet
@@ -693,6 +686,58 @@ struct SledInfo {
693686
request: SledRequest,
694687
}
695688

689+
impl SledInfo {
690+
fn new(
691+
sled_id: Uuid,
692+
subnet: Ipv6Subnet<SLED_PREFIX>,
693+
sled_address: SocketAddrV6,
694+
u2_zpools: Vec<ZpoolName>,
695+
is_scrimlet: bool,
696+
) -> SledInfo {
697+
SledInfo {
698+
sled_id,
699+
subnet,
700+
sled_address,
701+
u2_zpools,
702+
u2_zpool_allocators: HashMap::new(),
703+
is_scrimlet,
704+
addr_alloc: AddressBumpAllocator::new(subnet),
705+
request: Default::default(),
706+
}
707+
}
708+
709+
/// Allocates a dataset of the specified type from one of the U.2 pools on
710+
/// this Sled
711+
fn alloc_from_u2_zpool(
712+
&mut self,
713+
kind: DatasetKind,
714+
) -> Result<DatasetName, PlanError> {
715+
// We have two goals here:
716+
//
717+
// - For datasets of different types, they should be able to use the
718+
// same pool.
719+
//
720+
// - For datasets of the same type, they must be on separate pools. We
721+
// want to fail explicitly if we can't do that (which might happen if
722+
// we've tried to allocate more datasets than we have pools). Sled
723+
// Agent does not support having multiple datasets of some types
724+
// (e.g., cockroachdb) on the same pool.
725+
//
726+
// To achieve this, we maintain one iterator per dataset kind that
727+
// enumerates the valid zpool indexes.
728+
let allocator = self
729+
.u2_zpool_allocators
730+
.entry(kind.clone())
731+
.or_insert_with(|| Box::new(0..self.u2_zpools.len()));
732+
match allocator.next() {
733+
None => Err(PlanError::NotEnoughSleds),
734+
Some(which_zpool) => {
735+
Ok(DatasetName::new(self.u2_zpools[which_zpool].clone(), kind))
736+
}
737+
}
738+
}
739+
}
740+
696741
struct ServicePortBuilder {
697742
next_snat_ip: Option<IpAddr>,
698743
next_snat_port: Wrapping<u16>,

0 commit comments

Comments
 (0)