Skip to content

Commit 1fc3373

Browse files
committed
Collect internal DNS generation in inventory
1 parent 5f2c4dd commit 1fc3373

File tree

14 files changed

+267
-7
lines changed

14 files changed

+267
-7
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

nexus/db-model/src/inventory.rs

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ use nexus_db_schema::schema::inv_zone_manifest_zone;
3030
use nexus_db_schema::schema::{
3131
hw_baseboard_id, inv_caboose, inv_clickhouse_keeper_membership,
3232
inv_cockroachdb_status, inv_collection, inv_collection_error, inv_dataset,
33-
inv_host_phase_1_flash_hash, inv_last_reconciliation_dataset_result,
33+
inv_host_phase_1_flash_hash, inv_internal_dns,
34+
inv_last_reconciliation_dataset_result,
3435
inv_last_reconciliation_disk_result,
3536
inv_last_reconciliation_orphaned_dataset,
3637
inv_last_reconciliation_zone_result, inv_mupdate_override_non_boot,
@@ -60,8 +61,9 @@ use nexus_sled_agent_shared::inventory::{
6061
OmicronZoneDataset, OmicronZoneImageSource, OmicronZoneType,
6162
};
6263
use nexus_types::inventory::{
63-
BaseboardId, Caboose, CockroachStatus, Collection, NvmeFirmware,
64-
PowerState, RotPage, RotSlot, TimeSync,
64+
BaseboardId, Caboose, CockroachStatus, Collection,
65+
InternalDnsGenerationStatus, NvmeFirmware, PowerState, RotPage, RotSlot,
66+
TimeSync,
6567
};
6668
use omicron_common::api::external;
6769
use omicron_common::api::internal::shared::NetworkInterface;
@@ -2860,6 +2862,36 @@ impl From<InvNtpTimesync> for nexus_types::inventory::TimeSync {
28602862
}
28612863
}
28622864

2865+
#[derive(Queryable, Clone, Debug, Selectable, Insertable)]
2866+
#[diesel(table_name = inv_internal_dns)]
2867+
pub struct InvInternalDns {
2868+
pub inv_collection_id: DbTypedUuid<CollectionKind>,
2869+
pub zone_id: DbTypedUuid<OmicronZoneKind>,
2870+
pub generation: Generation,
2871+
}
2872+
2873+
impl InvInternalDns {
2874+
pub fn new(
2875+
inv_collection_id: CollectionUuid,
2876+
status: &InternalDnsGenerationStatus,
2877+
) -> Result<Self, anyhow::Error> {
2878+
Ok(Self {
2879+
inv_collection_id: inv_collection_id.into(),
2880+
zone_id: status.zone_id.into(),
2881+
generation: Generation(status.generation),
2882+
})
2883+
}
2884+
}
2885+
2886+
impl From<InvInternalDns> for InternalDnsGenerationStatus {
2887+
fn from(value: InvInternalDns) -> Self {
2888+
Self {
2889+
zone_id: value.zone_id.into(),
2890+
generation: value.generation.into(),
2891+
}
2892+
}
2893+
}
2894+
28632895
#[cfg(test)]
28642896
mod test {
28652897
use nexus_types::inventory::NvmeFirmware;

nexus/db-model/src/schema_versions.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use std::{collections::BTreeMap, sync::LazyLock};
1616
///
1717
/// This must be updated when you change the database schema. Refer to
1818
/// schema/crdb/README.adoc in the root of this repository for details.
19-
pub const SCHEMA_VERSION: Version = Version::new(169, 0, 0);
19+
pub const SCHEMA_VERSION: Version = Version::new(170, 0, 0);
2020

2121
/// List of all past database schema versions, in *reverse* order
2222
///
@@ -28,6 +28,7 @@ static KNOWN_VERSIONS: LazyLock<Vec<KnownVersion>> = LazyLock::new(|| {
2828
// | leaving the first copy as an example for the next person.
2929
// v
3030
// KnownVersion::new(next_int, "unique-dirname-with-the-sql-files"),
31+
KnownVersion::new(170, "inv-internal-dns"),
3132
KnownVersion::new(169, "inv-ntp-timesync"),
3233
KnownVersion::new(168, "add-inv-host-phase-1-flash-hash"),
3334
KnownVersion::new(167, "add-pending-mgs-updates-rot"),

nexus/db-queries/src/db/datastore/inventory.rs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ use nexus_db_model::InvConfigReconcilerStatus;
4141
use nexus_db_model::InvConfigReconcilerStatusKind;
4242
use nexus_db_model::InvDataset;
4343
use nexus_db_model::InvHostPhase1FlashHash;
44+
use nexus_db_model::InvInternalDns;
4445
use nexus_db_model::InvLastReconciliationDatasetResult;
4546
use nexus_db_model::InvLastReconciliationDiskResult;
4647
use nexus_db_model::InvLastReconciliationOrphanedDataset;
@@ -96,6 +97,7 @@ use nexus_sled_agent_shared::inventory::ZoneManifestNonBootInventory;
9697
use nexus_types::inventory::BaseboardId;
9798
use nexus_types::inventory::CockroachStatus;
9899
use nexus_types::inventory::Collection;
100+
use nexus_types::inventory::InternalDnsGenerationStatus;
99101
use nexus_types::inventory::PhysicalDiskFirmware;
100102
use nexus_types::inventory::SledAgent;
101103
use nexus_types::inventory::TimeSync;
@@ -398,6 +400,13 @@ impl DataStore {
398400
.collect::<Result<Vec<_>, _>>()
399401
.map_err(|e| Error::internal_error(&e.to_string()))?;
400402

403+
let inv_internal_dns_records: Vec<InvInternalDns> = collection
404+
.internal_dns_generation_status
405+
.iter()
406+
.map(|status| InvInternalDns::new(collection_id, status))
407+
.collect::<Result<Vec<_>, _>>()
408+
.map_err(|e| Error::internal_error(&e.to_string()))?;
409+
401410
// This implementation inserts all records associated with the
402411
// collection in one transaction. This is primarily for simplicity. It
403412
// means we don't have to worry about other readers seeing a
@@ -1516,6 +1525,15 @@ impl DataStore {
15161525
.await?;
15171526
}
15181527

1528+
// Insert the internal DNS generation status we've observed
1529+
if !inv_internal_dns_records.is_empty() {
1530+
use nexus_db_schema::schema::inv_internal_dns::dsl;
1531+
diesel::insert_into(dsl::inv_internal_dns)
1532+
.values(inv_internal_dns_records)
1533+
.execute_async(&conn)
1534+
.await?;
1535+
}
1536+
15191537
// Finally, insert the list of errors.
15201538
{
15211539
use nexus_db_schema::schema::inv_collection_error::dsl as errors_dsl;
@@ -1807,6 +1825,7 @@ impl DataStore {
18071825
nclickhouse_keeper_membership: usize,
18081826
ncockroach_status: usize,
18091827
nntp_timesync: usize,
1828+
ninternal_dns: usize,
18101829
}
18111830

18121831
let NumRowsDeleted {
@@ -1839,6 +1858,7 @@ impl DataStore {
18391858
nclickhouse_keeper_membership,
18401859
ncockroach_status,
18411860
nntp_timesync,
1861+
ninternal_dns,
18421862
} =
18431863
self.transaction_retry_wrapper("inventory_delete_collection")
18441864
.transaction(&conn, |conn| async move {
@@ -2117,6 +2137,18 @@ impl DataStore {
21172137
.await?
21182138
};
21192139

2140+
// Remove rows for internal DNS
2141+
let ninternal_dns = {
2142+
use nexus_db_schema::schema::inv_internal_dns::dsl;
2143+
diesel::delete(
2144+
dsl::inv_internal_dns.filter(
2145+
dsl::inv_collection_id.eq(db_collection_id),
2146+
),
2147+
)
2148+
.execute_async(&conn)
2149+
.await?
2150+
};
2151+
21202152
Ok(NumRowsDeleted {
21212153
ncollections,
21222154
nsps,
@@ -2147,6 +2179,7 @@ impl DataStore {
21472179
nclickhouse_keeper_membership,
21482180
ncockroach_status,
21492181
nntp_timesync,
2182+
ninternal_dns,
21502183
})
21512184
})
21522185
.await
@@ -2189,6 +2222,7 @@ impl DataStore {
21892222
"nclickhouse_keeper_membership" => nclickhouse_keeper_membership,
21902223
"ncockroach_status" => ncockroach_status,
21912224
"nntp_timesync" => nntp_timesync,
2225+
"ninternal_dns" => ninternal_dns,
21922226
);
21932227

21942228
Ok(())
@@ -3638,6 +3672,27 @@ impl DataStore {
36383672
.collect::<IdOrdMap<_>>()
36393673
};
36403674

3675+
// Load internal DNS generation status
3676+
let internal_dns_generation_status: IdOrdMap<
3677+
InternalDnsGenerationStatus,
3678+
> = {
3679+
use nexus_db_schema::schema::inv_internal_dns::dsl;
3680+
3681+
let records: Vec<InvInternalDns> = dsl::inv_internal_dns
3682+
.filter(dsl::inv_collection_id.eq(db_id))
3683+
.select(InvInternalDns::as_select())
3684+
.load_async(&*conn)
3685+
.await
3686+
.map_err(|e| {
3687+
public_error_from_diesel(e, ErrorHandler::Server)
3688+
})?;
3689+
3690+
records
3691+
.into_iter()
3692+
.map(|record| InternalDnsGenerationStatus::from(record))
3693+
.collect::<IdOrdMap<_>>()
3694+
};
3695+
36413696
// Finally, build up the sled-agent map using the sled agent and
36423697
// omicron zone rows. A for loop is easier to understand than into_iter
36433698
// + filter_map + return Result + collect.
@@ -3886,6 +3941,7 @@ impl DataStore {
38863941
clickhouse_keeper_cluster_membership,
38873942
cockroach_status,
38883943
ntp_timesync,
3944+
internal_dns_generation_status,
38893945
})
38903946
}
38913947
}

nexus/db-schema/src/schema.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1920,6 +1920,14 @@ table! {
19201920
}
19211921
}
19221922

1923+
table! {
1924+
inv_internal_dns (inv_collection_id, zone_id) {
1925+
inv_collection_id -> Uuid,
1926+
zone_id -> Uuid,
1927+
generation -> Int8,
1928+
}
1929+
}
1930+
19231931
/* blueprints */
19241932

19251933
table! {

nexus/inventory/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ base64.workspace = true
1313
camino.workspace = true
1414
chrono.workspace = true
1515
clickhouse-admin-keeper-client.workspace = true
16+
dns-service-client.workspace = true
1617
clickhouse-admin-server-client.workspace = true
1718
clickhouse-admin-types.workspace = true
1819
futures.workspace = true

nexus/inventory/src/builder.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ use nexus_types::inventory::CabooseWhich;
2626
use nexus_types::inventory::CockroachStatus;
2727
use nexus_types::inventory::Collection;
2828
use nexus_types::inventory::HostPhase1FlashHash;
29+
use nexus_types::inventory::InternalDnsGenerationStatus;
2930
use nexus_types::inventory::RotPage;
3031
use nexus_types::inventory::RotPageFound;
3132
use nexus_types::inventory::RotPageWhich;
@@ -127,6 +128,7 @@ pub struct CollectionBuilder {
127128
BTreeSet<ClickhouseKeeperClusterMembership>,
128129
cockroach_status: BTreeMap<NodeId, CockroachStatus>,
129130
ntp_timesync: IdOrdMap<TimeSync>,
131+
internal_dns_generation_status: IdOrdMap<InternalDnsGenerationStatus>,
130132
// CollectionBuilderRng is taken by value, rather than passed in as a
131133
// mutable ref, to encourage a tree-like structure where each RNG is
132134
// generally independent.
@@ -159,6 +161,7 @@ impl CollectionBuilder {
159161
clickhouse_keeper_cluster_membership: BTreeSet::new(),
160162
cockroach_status: BTreeMap::new(),
161163
ntp_timesync: IdOrdMap::new(),
164+
internal_dns_generation_status: IdOrdMap::new(),
162165
rng: CollectionBuilderRng::from_entropy(),
163166
}
164167
}
@@ -184,6 +187,7 @@ impl CollectionBuilder {
184187
.clickhouse_keeper_cluster_membership,
185188
cockroach_status: self.cockroach_status,
186189
ntp_timesync: self.ntp_timesync,
190+
internal_dns_generation_status: self.internal_dns_generation_status,
187191
}
188192
}
189193

@@ -652,6 +656,19 @@ impl CollectionBuilder {
652656
metrics.get_metric_unsigned(CockroachMetric::LivenessLiveNodes);
653657
self.cockroach_status.insert(node_id, status);
654658
}
659+
660+
/// Record information about internal DNS generation status
661+
pub fn found_internal_dns_generation_status(
662+
&mut self,
663+
status: InternalDnsGenerationStatus,
664+
) -> Result<(), anyhow::Error> {
665+
self.internal_dns_generation_status
666+
.insert_unique(status)
667+
.map_err(|err| err.into_owned())
668+
.context(
669+
"Internal DNS server reported generation status multiple times",
670+
)
671+
}
655672
}
656673

657674
/// Returns the current time, truncated to the previous microsecond.
@@ -712,6 +729,7 @@ mod test {
712729
assert!(collection.clickhouse_keeper_cluster_membership.is_empty());
713730
assert!(collection.cockroach_status.is_empty());
714731
assert!(collection.ntp_timesync.is_empty());
732+
assert!(collection.internal_dns_generation_status.is_empty());
715733
}
716734

717735
// Simple test of a single, fairly typical collection that contains just

0 commit comments

Comments
 (0)