Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
8 changes: 4 additions & 4 deletions Cargo.lock

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

7 changes: 6 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -964,11 +964,16 @@ opt-level = 3
# propolis-client = { path = "../propolis/lib/propolis-client" }
# propolis-mock-server = { path = "../propolis/bin/mock-server" }

# [patch."https://github.com/oxidecomputer/tufaceous"]
[patch."https://github.com/oxidecomputer/tufaceous"]
# tufaceous = { path = "../tufaceous/bin" }
# tufaceous-artifact = { path = "../tufaceous/artifact" }
# tufaceous-brand-metadata = { path = "../tufaceous/brand-metadata" }
# tufaceous-lib = { path = "../tufaceous/lib" }
# Extra slash here to pretend to be a different source.
tufaceous = { git = "https://github.com//oxidecomputer/tufaceous", branch = "sunshowers/spr/add-support-for-an-installinator-document" }
tufaceous-artifact = { git = "https://github.com//oxidecomputer/tufaceous", branch = "sunshowers/spr/add-support-for-an-installinator-document" }
tufaceous-brand-metadata = { git = "https://github.com//oxidecomputer/tufaceous", branch = "sunshowers/spr/add-support-for-an-installinator-document" }
tufaceous-lib = { git = "https://github.com//oxidecomputer/tufaceous", branch = "sunshowers/spr/add-support-for-an-installinator-document" }

# [patch."https://github.com/oxidecomputer/typify"]
# typify = { path = "../typify/typify" }
Expand Down
2 changes: 2 additions & 0 deletions dev-tools/releng/src/tuf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ use tokio::io::AsyncReadExt;
use tufaceous_artifact::ArtifactHash;
use tufaceous_artifact::ArtifactVersion;
use tufaceous_artifact::KnownArtifactKind;
use tufaceous_lib::IncludeInstallinatorDocument;
use tufaceous_lib::Key;
use tufaceous_lib::assemble::ArtifactManifest;
use tufaceous_lib::assemble::DeserializedArtifactData;
Expand Down Expand Up @@ -143,6 +144,7 @@ pub(crate) async fn build_tuf_repo(
manifest,
keys,
expiry,
IncludeInstallinatorDocument::Yes,
output_dir.join("repo.zip"),
)
.build()
Expand Down
3 changes: 3 additions & 0 deletions installinator-common/src/progress.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ impl StepSpec for InstallinatorSpec {
)]
#[serde(rename_all = "snake_case")]
pub enum InstallinatorComponent {
/// The installinator document.
InstallinatorDocument,

/// The host phase 2 component.
HostPhase2,

Expand Down
98 changes: 86 additions & 12 deletions installinator/src/artifact.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,19 @@ use installinator_common::EventReport;
use ipcc::{InstallinatorImageId, Ipcc};
use omicron_uuid_kinds::MupdateUuid;
use tokio::sync::mpsc;
use tufaceous_artifact::{ArtifactHash, ArtifactHashId};
use tufaceous_artifact::{
ArtifactHash, ArtifactHashId, ArtifactKind, KnownArtifactKind,
};

use crate::{errors::HttpError, fetch::FetchReceiver};

#[derive(Clone, Debug, Eq, PartialEq, Args)]
pub(crate) struct ArtifactIdOpts {
/// Retrieve artifact ID from IPCC
#[clap(long, required_unless_present_any = ["update_id", "host_phase_2", "control_plane"])]
#[clap(
long,
required_unless_present_any = ["update_id", "host_phase_2", "control_plane", "installinator_doc"]
)]
from_ipcc: bool,

#[clap(
Expand All @@ -31,31 +36,100 @@ pub(crate) struct ArtifactIdOpts {

#[clap(
long,
conflicts_with = "from_ipcc",
required_unless_present = "from_ipcc"
conflicts_with_all = ["from_ipcc", "installinator_doc"],
required_unless_present_any = ["from_ipcc", "installinator_doc"],
)]
host_phase_2: Option<ArtifactHash>,

#[clap(
long,
conflicts_with = "from_ipcc",
required_unless_present = "from_ipcc"
conflicts_with_all = ["from_ipcc", "installinator_doc"],
required_unless_present_any = ["from_ipcc", "installinator_doc"],
)]
control_plane: Option<ArtifactHash>,

#[clap(
long,
conflicts_with_all = ["from_ipcc", "host_phase_2", "control_plane"],
required_unless_present_any = ["from_ipcc", "host_phase_2", "control_plane"],
)]
installinator_doc: Option<ArtifactHash>,
}

impl ArtifactIdOpts {
pub(crate) fn resolve(&self) -> Result<InstallinatorImageId> {
pub(crate) fn resolve(&self) -> Result<LookupId> {
if self.from_ipcc {
let ipcc = Ipcc::new().context("error opening IPCC")?;
ipcc.installinator_image_id()
.context("error retrieving installinator image ID")
let image_id = ipcc
.installinator_image_id()
.context("error retrieving installinator image ID")?;
Ok(LookupId::from_image_id(&image_id))
} else {
let update_id = self.update_id.unwrap();
let host_phase_2 = self.host_phase_2.unwrap();
let control_plane = self.control_plane.unwrap();
let kind =
if let Some(installinator_doc_hash) = self.installinator_doc {
LookupIdKind::Document(installinator_doc_hash)
} else {
LookupIdKind::Hashes {
host_phase_2: self.host_phase_2.unwrap(),
control_plane: self.control_plane.unwrap(),
}
};

Ok(LookupId { update_id, kind })
}
}
}

/// Identifiers used by installinator to retrieve artifacts.
pub(crate) struct LookupId {
pub(crate) update_id: MupdateUuid,
pub(crate) kind: LookupIdKind,
}

impl LookupId {
fn from_image_id(image_id: &InstallinatorImageId) -> Self {
// This sentinel hash is used to indicate that the host phase 2 hash is
// actually the hash to the installinator document.
let kind = if image_id.control_plane == ArtifactHash([0; 32]) {
LookupIdKind::Document(image_id.host_phase_2)
} else {
LookupIdKind::Hashes {
host_phase_2: image_id.host_phase_2,
control_plane: image_id.control_plane,
}
};

Self { update_id: image_id.update_id, kind }
}
}

/// Either an installinator document hash, or host phase 2 and control plane
/// hashes.
pub(crate) enum LookupIdKind {
Document(ArtifactHash),
Hashes { host_phase_2: ArtifactHash, control_plane: ArtifactHash },
}

/// The host phase 2 and control plane hashes to download.
#[derive(Clone, Debug)]
pub(crate) struct ArtifactsToDownload {
pub(crate) host_phase_2: ArtifactHash,
pub(crate) control_plane: ArtifactHash,
}

impl ArtifactsToDownload {
pub(crate) fn host_phase_2_id(&self) -> ArtifactHashId {
ArtifactHashId {
kind: ArtifactKind::HOST_PHASE_2,
hash: self.host_phase_2,
}
}

Ok(InstallinatorImageId { update_id, host_phase_2, control_plane })
pub(crate) fn control_plane_id(&self) -> ArtifactHashId {
ArtifactHashId {
kind: KnownArtifactKind::ControlPlane.into(),
hash: self.control_plane,
Comment on lines +121 to +132
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The use of ArtifactKind vs KnownArtifactKind looks weirdly asymmetric

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, it definitely is, though this just moves existing code.

}
}
}
Expand Down
Loading
Loading