Skip to content

Commit d2aa2c5

Browse files
authored
Plan zone updates for target release (#8024)
Plumb the TUF repo representing the current `target_release` through the policy and planner. Update one zone at a time to the control-plane artifacts in that repo. Non-Nexus zones are updated first, then Nexus.
1 parent 2d077d5 commit d2aa2c5

File tree

22 files changed

+883
-43
lines changed

22 files changed

+883
-43
lines changed

common/src/api/external/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -750,6 +750,10 @@ impl Generation {
750750
Generation(next_gen)
751751
}
752752

753+
pub const fn prev(&self) -> Option<Generation> {
754+
if self.0 > 1 { Some(Generation(self.0 - 1)) } else { None }
755+
}
756+
753757
pub const fn as_u64(self) -> u64 {
754758
self.0
755759
}

dev-tools/reconfigurator-cli/tests/output/cmds-expunge-newly-added-external-dns-stderr

Whitespace-only changes.

dev-tools/reconfigurator-cli/tests/output/cmds-expunge-newly-added-external-dns-stdout

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1160,6 +1160,7 @@ INFO sufficient InternalDns zones exist in plan, desired_count: 3, current_count
11601160
INFO added zone to sled, sled_id: a88790de-5962-4871-8686-61c1fd5b7094, kind: ExternalDns
11611161
INFO sufficient Nexus zones exist in plan, desired_count: 3, current_count: 3
11621162
INFO sufficient Oximeter zones exist in plan, desired_count: 0, current_count: 0
1163+
INFO some zones not yet up-to-date, sled_id: a88790de-5962-4871-8686-61c1fd5b7094
11631164
INFO will ensure cockroachdb setting, setting: cluster.preserve_downgrade_option, value: DoNotModify
11641165
generated blueprint 9c998c1d-1a7b-440a-ae0c-40f781dea6e2 based on parent blueprint 366b0b68-d80e-4bc1-abd3-dc69837847e0
11651166

dev-tools/reconfigurator-cli/tests/output/cmds-expunge-newly-added-internal-dns-stderr

Whitespace-only changes.

dev-tools/reconfigurator-cli/tests/output/cmds-expunge-newly-added-internal-dns-stdout

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1379,6 +1379,7 @@ INFO added zone to sled, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, kind: In
13791379
INFO sufficient ExternalDns zones exist in plan, desired_count: 3, current_count: 3
13801380
INFO sufficient Nexus zones exist in plan, desired_count: 3, current_count: 3
13811381
INFO sufficient Oximeter zones exist in plan, desired_count: 0, current_count: 0
1382+
INFO some zones not yet up-to-date, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763
13821383
INFO will ensure cockroachdb setting, setting: cluster.preserve_downgrade_option, value: DoNotModify
13831384
generated blueprint af934083-59b5-4bf6-8966-6fb5292c29e1 based on parent blueprint 58d5e830-0884-47d8-a7cd-b2b3751adeb4
13841385

nexus-sled-agent-shared/src/inventory.rs

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ use omicron_common::{
2222
DatasetConfig, DatasetManagementStatus, DiskManagementStatus,
2323
DiskVariant, OmicronPhysicalDiskConfig,
2424
},
25+
update::ArtifactId,
2526
zpool_name::ZpoolName,
2627
};
2728
use omicron_uuid_kinds::{DatasetUuid, OmicronZoneUuid};
@@ -33,7 +34,7 @@ use serde::{Deserialize, Serialize};
3334
// depend on sled-hardware-types.
3435
pub use sled_hardware_types::Baseboard;
3536
use strum::EnumIter;
36-
use tufaceous_artifact::ArtifactHash;
37+
use tufaceous_artifact::{ArtifactHash, KnownArtifactKind};
3738

3839
/// Identifies information about disks which may be attached to Sleds.
3940
#[derive(Clone, Debug, Deserialize, JsonSchema, Serialize)]
@@ -590,13 +591,14 @@ impl OmicronZoneType {
590591
///
591592
/// # String representations of this type
592593
///
593-
/// There are no fewer than four string representations for this type, all
594+
/// There are no fewer than five string representations for this type, all
594595
/// slightly different from each other.
595596
///
596597
/// 1. [`Self::zone_prefix`]: Used to construct zone names.
597598
/// 2. [`Self::service_prefix`]: Used to construct SMF service names.
598599
/// 3. [`Self::name_prefix`]: Used to construct `Name` instances.
599600
/// 4. [`Self::report_str`]: Used for reporting and testing.
601+
/// 5. [`Self::artifact_name`]: Used to match TUF artifact names.
600602
///
601603
/// There is no `Display` impl to ensure that users explicitly choose the
602604
/// representation they want. (Please play close attention to this! The
@@ -715,6 +717,39 @@ impl ZoneKind {
715717
ZoneKind::Oximeter => "oximeter",
716718
}
717719
}
720+
721+
/// Return a string used as an artifact name for control-plane zones.
722+
/// This is **not guaranteed** to be stable.
723+
pub fn artifact_name(self) -> &'static str {
724+
match self {
725+
ZoneKind::BoundaryNtp => "ntp",
726+
ZoneKind::Clickhouse => "clickhouse",
727+
ZoneKind::ClickhouseKeeper => "clickhouse_keeper",
728+
ZoneKind::ClickhouseServer => "clickhouse",
729+
ZoneKind::CockroachDb => "cockroachdb",
730+
ZoneKind::Crucible => "crucible-zone",
731+
ZoneKind::CruciblePantry => "crucible-pantry-zone",
732+
ZoneKind::ExternalDns => "external-dns",
733+
ZoneKind::InternalDns => "internal-dns",
734+
ZoneKind::InternalNtp => "ntp",
735+
ZoneKind::Nexus => "nexus",
736+
ZoneKind::Oximeter => "oximeter",
737+
}
738+
}
739+
740+
/// Return true if an artifact represents a control plane zone image
741+
/// of this kind.
742+
pub fn is_control_plane_zone_artifact(
743+
self,
744+
artifact_id: &ArtifactId,
745+
) -> bool {
746+
artifact_id
747+
.kind
748+
.to_known()
749+
.map(|kind| matches!(kind, KnownArtifactKind::Zone))
750+
.unwrap_or(false)
751+
&& artifact_id.name == self.artifact_name()
752+
}
718753
}
719754

720755
/// Where Sled Agent should get the image for a zone.

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2249,7 +2249,7 @@ mod tests {
22492249
const SYSTEM_HASH: ArtifactHash = ArtifactHash([3; 32]);
22502250

22512251
datastore
2252-
.update_tuf_repo_insert(
2252+
.tuf_repo_insert(
22532253
opctx,
22542254
&TufRepoDescription {
22552255
repo: TufRepoMeta {

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

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@
77
use super::DataStore;
88
use crate::authz;
99
use crate::context::OpContext;
10-
use crate::db::model::{SemverVersion, TargetRelease, TargetReleaseSource};
10+
use crate::db::model::{
11+
Generation, SemverVersion, TargetRelease, TargetReleaseSource,
12+
};
1113
use async_bb8_diesel::AsyncRunQueryDsl as _;
1214
use diesel::insert_into;
1315
use diesel::prelude::*;
@@ -44,6 +46,25 @@ impl DataStore {
4446
Ok(current)
4547
}
4648

49+
/// Fetch a target release by generation number.
50+
pub async fn target_release_get_generation(
51+
&self,
52+
opctx: &OpContext,
53+
generation: Generation,
54+
) -> LookupResult<Option<TargetRelease>> {
55+
opctx
56+
.authorize(authz::Action::Read, &authz::TARGET_RELEASE_CONFIG)
57+
.await?;
58+
let conn = self.pool_connection_authorized(opctx).await?;
59+
dsl::target_release
60+
.select(TargetRelease::as_select())
61+
.filter(dsl::generation.eq(generation))
62+
.first_async(&*conn)
63+
.await
64+
.optional()
65+
.map_err(|e| public_error_from_diesel(e, ErrorHandler::Server))
66+
}
67+
4768
/// Insert a new target release row and return it. It will only become
4869
/// the current target release if its generation is larger than any
4970
/// existing row.
@@ -189,7 +210,7 @@ mod test {
189210
.parse()
190211
.expect("SHA256('')");
191212
let repo = datastore
192-
.update_tuf_repo_insert(
213+
.tuf_repo_insert(
193214
opctx,
194215
&TufRepoDescription {
195216
repo: TufRepoMeta {

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

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,21 @@ use diesel::result::Error as DieselError;
1717
use nexus_db_errors::OptionalError;
1818
use nexus_db_errors::{ErrorHandler, public_error_from_diesel};
1919
use nexus_db_lookup::DbConnection;
20-
use nexus_db_model::{ArtifactHash, TufArtifact, TufRepo, TufRepoDescription};
20+
use nexus_db_model::{
21+
ArtifactHash, TufArtifact, TufRepo, TufRepoDescription, to_db_typed_uuid,
22+
};
2123
use omicron_common::api::external::{
2224
self, CreateResult, DataPageParams, Generation, ListResultVec,
2325
LookupResult, LookupType, ResourceType, TufRepoInsertStatus,
2426
};
27+
use omicron_uuid_kinds::GenericUuid;
2528
use omicron_uuid_kinds::TufRepoKind;
2629
use omicron_uuid_kinds::TypedUuid;
2730
use swrite::{SWrite, swrite};
2831
use tufaceous_artifact::ArtifactVersion;
2932
use uuid::Uuid;
3033

31-
/// The return value of [`DataStore::update_tuf_repo_insert`].
34+
/// The return value of [`DataStore::tuf_repo_insert`].
3235
///
3336
/// This is similar to [`external::TufRepoInsertResponse`], but uses
3437
/// nexus-db-model's types instead of external types.
@@ -75,7 +78,7 @@ impl DataStore {
7578
/// `TufRepoDescription` if one was already found. (This is not an upsert,
7679
/// because if we know about an existing repo but with different contents,
7780
/// we reject that.)
78-
pub async fn update_tuf_repo_insert(
81+
pub async fn tuf_repo_insert(
7982
&self,
8083
opctx: &OpContext,
8184
description: &external::TufRepoDescription,
@@ -106,8 +109,40 @@ impl DataStore {
106109
})
107110
}
108111

112+
/// Returns a TUF repo description.
113+
pub async fn tuf_repo_get_by_id(
114+
&self,
115+
opctx: &OpContext,
116+
repo_id: TypedUuid<TufRepoKind>,
117+
) -> LookupResult<TufRepoDescription> {
118+
opctx.authorize(authz::Action::Read, &authz::FLEET).await?;
119+
120+
use nexus_db_schema::schema::tuf_repo::dsl;
121+
122+
let conn = self.pool_connection_authorized(opctx).await?;
123+
let repo = dsl::tuf_repo
124+
.filter(dsl::id.eq(to_db_typed_uuid(repo_id)))
125+
.select(TufRepo::as_select())
126+
.first_async::<TufRepo>(&*conn)
127+
.await
128+
.map_err(|e| {
129+
public_error_from_diesel(
130+
e,
131+
ErrorHandler::NotFoundByLookup(
132+
ResourceType::TufRepo,
133+
LookupType::ById(repo_id.into_untyped_uuid()),
134+
),
135+
)
136+
})?;
137+
138+
let artifacts = artifacts_for_repo(repo.id.into(), &conn)
139+
.await
140+
.map_err(|e| public_error_from_diesel(e, ErrorHandler::Server))?;
141+
Ok(TufRepoDescription { repo, artifacts })
142+
}
143+
109144
/// Returns the TUF repo description corresponding to this system version.
110-
pub async fn update_tuf_repo_get(
145+
pub async fn tuf_repo_get_by_version(
111146
&self,
112147
opctx: &OpContext,
113148
system_version: SemverVersion,
@@ -140,7 +175,7 @@ impl DataStore {
140175
}
141176

142177
/// Returns the list of all TUF repo artifacts known to the system.
143-
pub async fn update_tuf_artifact_list(
178+
pub async fn tuf_list_repos(
144179
&self,
145180
opctx: &OpContext,
146181
generation: Generation,
@@ -160,7 +195,7 @@ impl DataStore {
160195
}
161196

162197
/// Returns the current TUF repo generation number.
163-
pub async fn update_tuf_generation_get(
198+
pub async fn tuf_get_generation(
164199
&self,
165200
opctx: &OpContext,
166201
) -> LookupResult<Generation> {

nexus/reconfigurator/execution/src/dns.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1496,6 +1496,8 @@ mod test {
14961496
target_crucible_pantry_zone_count: CRUCIBLE_PANTRY_REDUNDANCY,
14971497
clickhouse_policy: None,
14981498
oximeter_read_policy: OximeterReadPolicy::new(1),
1499+
tuf_repo: None,
1500+
old_repo: None,
14991501
log,
15001502
}
15011503
.build()

0 commit comments

Comments
 (0)