Skip to content

[15/n] send resolver status up via inventory #8300

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 4 commits into
base: sunshowers/spr/main.13n-send-resolver-status-up-via-inventory
Choose a base branch
from
Draft
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
7 changes: 7 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 11 additions & 2 deletions common/src/update/zone_manifest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@

use iddqd::{IdOrdItem, IdOrdMap, id_upcast};
use omicron_uuid_kinds::MupdateUuid;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use tufaceous_artifact::ArtifactHash;

/// Describes the set of Omicron zones written out into an install dataset.
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize, JsonSchema)]
pub struct OmicronZoneManifest {
/// The UUID of the mupdate which created this manifest. Intended primarily
/// for checking equality.
Expand All @@ -27,7 +28,15 @@ impl OmicronZoneManifest {
///
/// Part of [`OmicronZoneManifest`].
#[derive(
Clone, Debug, Eq, Ord, PartialEq, PartialOrd, Deserialize, Serialize,
Clone,
Debug,
Eq,
Ord,
PartialEq,
PartialOrd,
Deserialize,
Serialize,
JsonSchema,
)]
pub struct OmicronZoneFileMetadata {
/// The file name.
Expand Down
1 change: 1 addition & 0 deletions nexus-sled-agent-shared/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ edition = "2021"
workspace = true

[dependencies]
camino.workspace = true
chrono.workspace = true
daft.workspace = true
id-map.workspace = true
Expand Down
199 changes: 197 additions & 2 deletions nexus-sled-agent-shared/src/inventory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use std::collections::BTreeMap;
use std::net::{IpAddr, Ipv6Addr, SocketAddr, SocketAddrV6};
use std::time::Duration;

use camino::Utf8PathBuf;
use chrono::{DateTime, Utc};
use daft::Diffable;
use id_map::IdMap;
Expand All @@ -23,13 +24,15 @@ use omicron_common::{
internal::shared::{NetworkInterface, SourceNatConfig},
},
disk::{DatasetConfig, DiskVariant, OmicronPhysicalDiskConfig},
snake_case_result::{self, SnakeCaseResult},
update::ArtifactId,
zpool_name::ZpoolName,
};
use omicron_uuid_kinds::{DatasetUuid, OmicronZoneUuid};
use omicron_uuid_kinds::{DatasetUuid, MupdateUuid, OmicronZoneUuid};
use omicron_uuid_kinds::{MupdateOverrideUuid, PhysicalDiskUuid};
use omicron_uuid_kinds::{SledUuid, ZpoolUuid};
use schemars::JsonSchema;
use schemars::schema::{Schema, SchemaObject};
use schemars::{JsonSchema, SchemaGenerator};
use serde::{Deserialize, Serialize};
// Export this type for convenience -- this way, dependents don't have to
// depend on sled-hardware-types.
Expand Down Expand Up @@ -119,6 +122,7 @@ pub struct Inventory {
pub ledgered_sled_config: Option<OmicronSledConfig>,
pub reconciler_status: ConfigReconcilerInventoryStatus,
pub last_reconciliation: Option<ConfigReconcilerInventory>,
pub zone_image_resolver: ZoneImageResolverInventory,
}

/// Describes the last attempt made by the sled-agent-config-reconciler to
Expand Down Expand Up @@ -241,6 +245,189 @@ pub enum ConfigReconcilerInventoryStatus {
Idle { completed_at: DateTime<Utc>, ran_for: Duration },
}

/// A simplified form of zone image resolver status.
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, JsonSchema, Serialize)]
pub struct ZoneImageResolverInventory {
/// The zone manifest status.
pub zone_manifest: ZoneManifestInventory,

/// The mupdate override status.
pub mupdate_override: MupdateOverrideInventory,
}

impl ZoneImageResolverInventory {
/// Returns a new, fake inventory for tests.
pub fn new_fake() -> Self {
Self {
zone_manifest: ZoneManifestInventory::new_fake(),
mupdate_override: MupdateOverrideInventory::new_fake(),
}
}
}

#[derive(Clone, Debug, PartialEq, Eq, Deserialize, JsonSchema, Serialize)]
pub struct ZoneManifestInventory {
/// The path to the zone manifest file on the boot disk.
#[schemars(schema_with = "path_schema")]
pub boot_disk_path: Utf8PathBuf,

/// The manifest read from disk.
#[serde(with = "snake_case_result")]
#[schemars(
schema_with = "SnakeCaseResult::<ZoneArtifactsInventory, String>::json_schema"
)]
pub manifest: Result<ZoneArtifactsInventory, String>,

/// Warnings about non-boot disks, if any.
pub non_boot_status: IdOrdMap<ZoneManifestNonBootInventory>,
}

impl ZoneManifestInventory {
/// Returns a new, fake inventory for tests.
pub fn new_fake() -> Self {
Self {
boot_disk_path: Utf8PathBuf::from("/fake/path/install/zones.json"),
manifest: Ok(ZoneArtifactsInventory::new_fake()),
non_boot_status: IdOrdMap::new(),
}
}
}

#[derive(Clone, Debug, PartialEq, Eq, Deserialize, JsonSchema, Serialize)]
pub struct ZoneArtifactsInventory {
/// The mupdate UUID that created this inventory.
pub mupdate_id: MupdateUuid,

/// The artifacts on disk.
pub artifacts: IdOrdMap<ZoneArtifactInventory>,
}

impl ZoneArtifactsInventory {
/// Returns a new, fake inventory for tests.
pub fn new_fake() -> Self {
Self {
mupdate_id: MupdateUuid::nil(),
// TODO: fill out some fake zones here? maybe a representative
// selection of real zones?
artifacts: IdOrdMap::new(),
}
}
}

#[derive(Clone, Debug, PartialEq, Eq, Deserialize, JsonSchema, Serialize)]
pub struct ZoneArtifactInventory {
/// The filename.
pub file_name: String,

/// The full path to the file.
#[schemars(schema_with = "path_schema")]
pub path: Utf8PathBuf,

/// The expected size of the file.
pub expected_size: u64,

/// The expected hash of the file.
pub expected_hash: ArtifactHash,

/// The status.
#[serde(with = "snake_case_result")]
#[schemars(schema_with = "SnakeCaseResult::<(), String>::json_schema")]
pub status: Result<(), String>,
}

impl IdOrdItem for ZoneArtifactInventory {
type Key<'a> = &'a str;
fn key(&self) -> Self::Key<'_> {
&self.file_name
}
id_upcast!();
}

#[derive(Clone, Debug, PartialEq, Eq, Deserialize, JsonSchema, Serialize)]
pub struct ZoneManifestNonBootInventory {
/// The non-boot zpool ID.
pub zpool_id: ZpoolUuid,

/// The path to the zone manifest JSON on the non-boot disk.
#[schemars(schema_with = "path_schema")]
pub path: Utf8PathBuf,

/// Whether the status is valid.
pub is_valid: bool,

/// A message describing the status. If `is_valid` is false, then this
/// message describes the reason for the invalid status.
pub message: String,
}

impl IdOrdItem for ZoneManifestNonBootInventory {
type Key<'a> = ZpoolUuid;
fn key(&self) -> Self::Key<'_> {
self.zpool_id
}
id_upcast!();
}

#[derive(Clone, Debug, PartialEq, Eq, Deserialize, JsonSchema, Serialize)]
pub struct MupdateOverrideInventory {
/// The path to the mupdate override JSON on the boot disk.
#[schemars(schema_with = "path_schema")]
pub boot_disk_path: Utf8PathBuf,

/// The boot disk override, or an error if it could not be parsed.
#[serde(with = "snake_case_result")]
#[schemars(schema_with = "SnakeCaseResult::<(), String>::json_schema")]
pub boot_disk_override:
Result<Option<MupdateOverrideInfoInventory>, String>,

/// Warnings about non-boot disks, if any.
pub non_boot_status: IdOrdMap<MupdateOverrideNonBootInventory>,
}

impl MupdateOverrideInventory {
/// Returns a new, fake inventory for tests.
pub fn new_fake() -> Self {
Self {
boot_disk_path: Utf8PathBuf::from(
"/fake/path/install/mupdate_override.json",
),
boot_disk_override: Ok(None),
non_boot_status: IdOrdMap::new(),
}
}
}

#[derive(Clone, Debug, PartialEq, Eq, Deserialize, JsonSchema, Serialize)]
pub struct MupdateOverrideInfoInventory {
/// The mupdate override UUID.
pub mupdate_override_id: MupdateOverrideUuid,
}

#[derive(Clone, Debug, PartialEq, Eq, Deserialize, JsonSchema, Serialize)]
pub struct MupdateOverrideNonBootInventory {
/// The non-boot zpool ID.
pub zpool_id: ZpoolUuid,

/// The path to the mupdate override JSON on the non-boot disk.
#[schemars(schema_with = "path_schema")]
pub path: Utf8PathBuf,

/// Whether the status is valid.
pub is_valid: bool,

/// A message describing the status. If `is_valid` is false, then this
/// message describes the reason for the invalid status.
pub message: String,
}

impl IdOrdItem for MupdateOverrideNonBootInventory {
type Key<'a> = ZpoolUuid;
fn key(&self) -> Self::Key<'_> {
self.zpool_id
}
id_upcast!();
}

/// Describes the role of the sled within the rack.
///
/// Note that this may change if the sled is physically moved
Expand Down Expand Up @@ -925,3 +1112,11 @@ mod tests {
}
}
}

// Used for schemars to be able to be used with camino:
// See https://github.com/camino-rs/camino/issues/91#issuecomment-2027908513
fn path_schema(generator: &mut SchemaGenerator) -> Schema {
let mut schema: SchemaObject = <String>::json_schema(generator).into();
schema.format = Some("Utf8PathBuf".to_owned());
schema.into()
}
1 change: 1 addition & 0 deletions nexus/db-model/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ clickhouse-admin-types.workspace = true
derive-where.workspace = true
diesel = { workspace = true, features = ["postgres", "r2d2", "chrono", "serde_json", "network-address", "uuid"] }
hex.workspace = true
iddqd.workspace = true
ipnetwork.workspace = true
macaddr.workspace = true
newtype_derive.workspace = true
Expand Down
Loading
Loading