Skip to content
Merged
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
17 changes: 17 additions & 0 deletions crates/trident/src/osimage/cosi/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,21 @@ pub enum CosiMetadataErrorKind {

#[error("OS package '{0}' is missing required architecture information")]
V1_1OsPackageMissingArch(String),

#[error("Image partition metadata is required for COSI version >= 1.2, but not provided")]
V1_2PartitionsRequired,

#[error(
"Partition {number} references path '{path}' which does not match any filesystem image"
)]
V1_2PartitionPathUnknown { number: u32, path: String },

#[error("Duplicate partition number: {0}")]
V1_2DuplicatePartitionNumber(u32),

#[error("Partition numbers must be 1-indexed; found partition number 0")]
V1_2PartitionNumberZero,

#[error("Image file at path '{0}' has no corresponding partition")]
V1_2ImageFileHasNoCorrespondingPartition(String),
}
65 changes: 60 additions & 5 deletions crates/trident/src/osimage/cosi/metadata.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::{cmp::Ordering, fmt::Display, path::PathBuf};
use std::{cmp::Ordering, fmt::Display, iter, path::PathBuf};

use anyhow::{ensure, Error};
use log::trace;
Expand Down Expand Up @@ -28,13 +28,19 @@ pub(super) enum KnownMetadataVersion {
///
/// Introduces bootloader metadata.
V1_1,

/// COSI metadata specification version 1.2.
///
/// Introduces partition metadata.
V1_2,
}

impl KnownMetadataVersion {
pub(super) fn as_version(&self) -> MetadataVersion {
match self {
KnownMetadataVersion::V1_0 => MetadataVersion { major: 1, minor: 0 },
KnownMetadataVersion::V1_1 => MetadataVersion { major: 1, minor: 1 },
Self::V1_0 => MetadataVersion { major: 1, minor: 0 },
Self::V1_1 => MetadataVersion { major: 1, minor: 1 },
Self::V1_2 => MetadataVersion { major: 1, minor: 2 },
}
}
}
Expand Down Expand Up @@ -91,6 +97,13 @@ pub(crate) struct CosiMetadata {
/// Template for a host configuration embedded within the image.
#[serde(default)]
pub host_configuration_template: Option<String>,

/// Original image partition metadata.
///
/// The order of `Partition` objects in the `partitions` array is
/// unspecified since the `number` field indicates the original ordering.
#[serde(default)]
pub partitions: Option<Vec<Partition>>,
}

impl CosiMetadata {
Expand Down Expand Up @@ -142,6 +155,19 @@ impl CosiMetadata {
pub(super) fn get_regular_filesystems(&self) -> impl Iterator<Item = &Image> {
self.images.iter().filter(|image| !image.is_esp())
}

/// Returns an iterator over all image files in the COSI metadata, including
/// verity files if present.
pub(super) fn image_files(&self) -> impl Iterator<Item = &ImageFile> {
self.images
// Iterate over all images
.iter()
// Get a flattened iterator over the image files and their verity files
// (if any)
.flat_map(|fs| {
iter::once(&fs.file).chain(fs.verity.as_ref().map(|verity| &verity.file))
})
}
}

#[derive(Debug, Clone, Copy, Eq, PartialEq)]
Expand Down Expand Up @@ -332,6 +358,33 @@ pub(crate) enum SystemdBootloaderType {
Unknown(String),
}

#[derive(Debug, Deserialize, Clone, Eq, PartialEq)]
#[serde(rename_all = "camelCase")]
pub(crate) struct Partition {
/// Absolute path of the compressed image file inside the tarball. MUST
/// start with `images/`.
pub path: Option<PathBuf>,

/// Size of the partition before any filesystem shrinking. SHOULD be at
/// least as large as the `uncompressedSize` field of the corresponding
/// `ImageFile` object (matched by `path`).
pub original_size: u64,

/// The partition type UUID.
pub part_type: Uuid,

/// The partition UUID.
pub part_uuid: Uuid,

/// Partition label (GPT partition name, may be an empty string).
#[serde(default)]
pub label: String,

/// The index where the partition originally appeared in the partition table
/// (1-indexed).
pub number: u32,
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down Expand Up @@ -378,14 +431,15 @@ mod tests {
#[test]
fn test_get_esp_filesystem() {
let mut metadata = CosiMetadata {
version: MetadataVersion { major: 1, minor: 0 },
version: KnownMetadataVersion::V1_0.as_version(),
os_arch: SystemArchitecture::Amd64,
os_release: OsRelease::default(),
images: vec![], // Empty images
os_packages: None,
id: None,
bootloader: None,
host_configuration_template: None,
partitions: None,
};

// No images
Expand Down Expand Up @@ -449,14 +503,15 @@ mod tests {
#[test]
fn test_get_regular_filesystems() {
let mut metadata = CosiMetadata {
version: MetadataVersion { major: 1, minor: 0 },
version: KnownMetadataVersion::V1_0.as_version(),
os_arch: SystemArchitecture::Amd64,
os_release: OsRelease::default(),
images: vec![], // Empty images
os_packages: None,
id: None,
bootloader: None,
host_configuration_template: None,
partitions: None,
};

// No images
Expand Down
8 changes: 6 additions & 2 deletions crates/trident/src/osimage/cosi/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,8 @@ mod tests {

use crate::osimage::OsImageFileSystemType;

use super::metadata::KnownMetadataVersion;

/// Generate a test tarball with the given entries.
///
/// An entry is a tuple of (path, data).
Expand Down Expand Up @@ -860,14 +862,15 @@ mod tests {
source: Url::parse("mock://").unwrap(),
entries,
metadata: CosiMetadata {
version: MetadataVersion { major: 1, minor: 0 },
version: KnownMetadataVersion::V1_0.as_version(),
id: Some(Uuid::new_v4()),
os_arch: SystemArchitecture::Amd64,
os_release: OsRelease::default(),
os_packages: None,
images,
bootloader: None,
host_configuration_template: None,
partitions: None,
},
reader: FileReader::Buffer(data),
metadata_sha384: Sha384Hash::from("0".repeat(96)),
Expand All @@ -881,14 +884,15 @@ mod tests {
source: Url::parse("mock://").unwrap(),
entries: HashMap::new(),
metadata: CosiMetadata {
version: MetadataVersion { major: 1, minor: 0 },
version: KnownMetadataVersion::V1_0.as_version(),
id: Some(Uuid::new_v4()),
os_arch: SystemArchitecture::Amd64,
os_release: OsRelease::default(),
images: vec![],
os_packages: None,
bootloader: None,
host_configuration_template: None,
partitions: None,
},
reader: FileReader::Buffer(Cursor::new(Vec::<u8>::new())),
metadata_sha384: Sha384Hash::from("0".repeat(96)),
Expand Down
Loading