Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
8fe97a9
target_release schema
plotnick Jan 15, 2025
7722d7c
target_release model
plotnick Jan 20, 2025
2010dca
target_release datastore methods
plotnick Jan 22, 2025
816970b
target_release API
plotnick Feb 10, 2025
1a5b455
One query to fetch the current target_release
plotnick Feb 11, 2025
fe23073
Move views into shared module
plotnick Feb 11, 2025
307bd2a
Merge branch 'main' into config-target-release
plotnick Feb 23, 2025
80f6902
InstallDataset → Unspecified, resolve tuf_repo_id
plotnick Feb 23, 2025
87b2000
Make version mandatory for setting target_release
plotnick Feb 24, 2025
5fe4bb3
Synthetic authz resource TargetReleaseConfig
plotnick Feb 24, 2025
7094077
Merge remote-tracking branch 'origin/main' into config-target-release
plotnick Feb 25, 2025
f141d8e
Don't panic!
plotnick Feb 26, 2025
fd908da
Merge remote-tracking branch 'origin/main' into config-target-release
plotnick Feb 26, 2025
5898757
Safer TargetRelease constructors
plotnick Mar 4, 2025
e7181db
Rework target release datastore methods
plotnick Mar 4, 2025
27b7e8d
Refactor target_release_view
plotnick Mar 4, 2025
8e33014
Internal error for missing TUF repo
plotnick Mar 4, 2025
a709786
PUT target-release
plotnick Mar 4, 2025
1a83b85
Further constrain tuf_repo_for_system_version
plotnick Mar 5, 2025
25a88b0
Publish hidden system/update endpoints
plotnick Mar 5, 2025
8d8c513
Merge remote-tracking branch 'origin/main' into config-target-release
plotnick Mar 5, 2025
09fd2f3
Improve target_release datastore test
plotnick Mar 6, 2025
ee5b389
Authz coverage for target_release endpoints
plotnick Mar 6, 2025
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
1 change: 1 addition & 0 deletions Cargo.lock

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

10 changes: 5 additions & 5 deletions common/src/api/external/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3091,10 +3091,10 @@ pub enum BfdMode {
/// A description of an uploaded TUF repository.
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, JsonSchema)]
pub struct TufRepoDescription {
// Information about the repository.
/// Information about the repository.
pub repo: TufRepoMeta,

// Information about the artifacts present in the repository.
/// Information about the artifacts present in the repository.
pub artifacts: Vec<TufArtifactMeta>,
}

Expand All @@ -3107,7 +3107,7 @@ impl TufRepoDescription {

/// Metadata about a TUF repository.
///
/// Found within a [`TufRepoDescription`].
/// Found within a `TufRepoDescription`.
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, JsonSchema)]
pub struct TufRepoMeta {
/// The hash of the repository.
Expand Down Expand Up @@ -3136,7 +3136,7 @@ pub struct TufRepoMeta {

/// Metadata about an individual TUF artifact.
///
/// Found within a [`TufRepoDescription`].
/// Found within a `TufRepoDescription`.
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, JsonSchema)]
pub struct TufArtifactMeta {
/// The artifact ID.
Expand All @@ -3162,7 +3162,7 @@ pub struct TufRepoInsertResponse {

/// Status of a TUF repo import.
///
/// Part of [`TufRepoInsertResponse`].
/// Part of `TufRepoInsertResponse`.
#[derive(
Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize, JsonSchema,
)]
Expand Down
43 changes: 43 additions & 0 deletions nexus/auth/src/authz/api_resources.rs
Original file line number Diff line number Diff line change
Expand Up @@ -668,6 +668,49 @@ impl AuthorizedResource for SiloUserList {
}
}

/// System software target version configuration
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct TargetReleaseConfig;

pub const TARGET_RELEASE_CONFIG: TargetReleaseConfig = TargetReleaseConfig;

impl oso::PolarClass for TargetReleaseConfig {
fn get_polar_class_builder() -> oso::ClassBuilder<Self> {
oso::Class::builder()
.with_equality_check()
.add_attribute_getter("fleet", |_: &TargetReleaseConfig| FLEET)
}
}

impl AuthorizedResource for TargetReleaseConfig {
fn load_roles<'fut>(
&'fut self,
opctx: &'fut OpContext,
authn: &'fut authn::Context,
roleset: &'fut mut RoleSet,
) -> futures::future::BoxFuture<'fut, Result<(), Error>> {
// There are no roles on the TargetReleaseConfig, only permissions. But we
// still need to load the Fleet-related roles to verify that the actor
// has the "admin" role on the Fleet (possibly conferred from a Silo
// role).
load_roles_for_resource_tree(&FLEET, opctx, authn, roleset).boxed()
}

fn on_unauthorized(
&self,
_: &Authz,
error: Error,
_: AnyActor,
_: Action,
) -> Error {
error
}

fn polar_class(&self) -> oso::Class {
Self::get_polar_class()
}
}

// Main resource hierarchy: Projects and their resources

authz_resource! {
Expand Down
14 changes: 14 additions & 0 deletions nexus/auth/src/authz/omicron.polar
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,20 @@ resource BlueprintConfig {
has_relation(fleet: Fleet, "parent_fleet", list: BlueprintConfig)
if list.fleet = fleet;

# Describes the policy for accessing blueprints
resource TargetReleaseConfig {
permissions = [
"read", # read the current target release
"modify", # change the current target release
];

relations = { parent_fleet: Fleet };
"read" if "viewer" on "parent_fleet";
"modify" if "admin" on "parent_fleet";
}
has_relation(fleet: Fleet, "parent_fleet", resource: TargetReleaseConfig)
if resource.fleet = fleet;

# Describes the policy for reading and modifying low-level inventory
resource Inventory {
permissions = [ "read", "modify" ];
Expand Down
1 change: 1 addition & 0 deletions nexus/auth/src/authz/oso_generic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ pub fn make_omicron_oso(log: &slog::Logger) -> Result<OsoInit, anyhow::Error> {
SiloCertificateList::get_polar_class(),
SiloIdentityProviderList::get_polar_class(),
SiloUserList::get_polar_class(),
TargetReleaseConfig::get_polar_class(),
];
for c in classes {
oso_builder = oso_builder.register_class(c)?;
Expand Down
2 changes: 2 additions & 0 deletions nexus/db-model/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ mod rendezvous_debug_dataset;
mod semver_version;
mod switch_interface;
mod switch_port;
mod target_release;
mod v2p_mapping;
mod vmm_state;
// These actually represent subqueries, not real table.
Expand Down Expand Up @@ -211,6 +212,7 @@ pub use support_bundle::*;
pub use switch::*;
pub use switch_interface::*;
pub use switch_port::*;
pub use target_release::*;
pub use tuf_repo::*;
pub use typed_uuid::to_db_typed_uuid;
pub use upstairs_repair::*;
Expand Down
9 changes: 9 additions & 0 deletions nexus/db-model/src/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1411,6 +1411,15 @@ allow_tables_to_appear_in_same_query!(
joinable!(tuf_repo_artifact -> tuf_repo (tuf_repo_id));
joinable!(tuf_repo_artifact -> tuf_artifact (tuf_artifact_id));

table! {
target_release (generation) {
generation -> Int8,
time_requested -> Timestamptz,
release_source -> crate::TargetReleaseSourceEnum,
tuf_repo_id -> Nullable<Uuid>,
}
}

table! {
support_bundle {
id -> Uuid,
Expand Down
3 changes: 2 additions & 1 deletion nexus/db-model/src/schema_versions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use std::{collections::BTreeMap, sync::LazyLock};
///
/// This must be updated when you change the database schema. Refer to
/// schema/crdb/README.adoc in the root of this repository for details.
pub const SCHEMA_VERSION: Version = Version::new(128, 0, 0);
pub const SCHEMA_VERSION: Version = Version::new(129, 0, 0);

/// List of all past database schema versions, in *reverse* order
///
Expand All @@ -28,6 +28,7 @@ static KNOWN_VERSIONS: LazyLock<Vec<KnownVersion>> = LazyLock::new(|| {
// | leaving the first copy as an example for the next person.
// v
// KnownVersion::new(next_int, "unique-dirname-with-the-sql-files"),
KnownVersion::new(129, "create-target-release"),
KnownVersion::new(128, "sled-resource-for-vmm"),
KnownVersion::new(127, "bp-disk-disposition-expunged-cleanup"),
KnownVersion::new(126, "affinity"),
Expand Down
77 changes: 77 additions & 0 deletions nexus/db-model/src/target_release.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

use super::{Generation, impl_enum_type};
use crate::schema::target_release;
use crate::typed_uuid::DbTypedUuid;
use chrono::{DateTime, Utc};
use nexus_types::external_api::views;
use omicron_uuid_kinds::TufRepoKind;

impl_enum_type!(
#[derive(SqlType, Debug, QueryId)]
#[diesel(postgres_type(name = "target_release_source", schema = "public"))]
pub struct TargetReleaseSourceEnum;

/// The source of the software release that should be deployed to the rack.
#[derive(Copy, Clone, Debug, AsExpression, FromSqlRow, PartialEq, Eq, Hash)]
#[diesel(sql_type = TargetReleaseSourceEnum)]
pub enum TargetReleaseSource;

Unspecified => b"unspecified"
SystemVersion => b"system_version"
);

/// Specify the target system software release.
#[derive(Clone, Debug, Insertable, Queryable, Selectable)]
#[diesel(table_name = target_release)]
pub struct TargetRelease {
/// Each change to the target release is recorded as a row with
/// a monotonically increasing generation number. The row with
/// the largest generation is the current target release.
pub generation: Generation,

/// The time at which this target release was requested.
pub time_requested: DateTime<Utc>,

/// The source of the target release.
pub release_source: TargetReleaseSource,

/// The TUF repo containing the target release.
pub tuf_repo_id: Option<DbTypedUuid<TufRepoKind>>,
}

impl TargetRelease {
pub fn new_unspecified(prev: &TargetRelease) -> Self {
Self {
generation: Generation(prev.generation.next()),
time_requested: Utc::now(),
release_source: TargetReleaseSource::Unspecified,
tuf_repo_id: None,
}
}

pub fn new_system_version(
prev: &TargetRelease,
tuf_repo_id: DbTypedUuid<TufRepoKind>,
) -> Self {
Self {
generation: Generation(prev.generation.next()),
time_requested: Utc::now(),
release_source: TargetReleaseSource::SystemVersion,
tuf_repo_id: Some(tuf_repo_id),
}
}

pub fn into_external(
&self,
release_source: views::TargetReleaseSource,
) -> views::TargetRelease {
views::TargetRelease {
generation: (&self.generation.0).into(),
time_requested: self.time_requested,
release_source,
}
}
}
1 change: 1 addition & 0 deletions nexus/db-queries/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ strum.workspace = true
swrite.workspace = true
thiserror.workspace = true
tokio = { workspace = true, features = ["full"] }
tufaceous-artifact.workspace = true
url.workspace = true
usdt.workspace = true
uuid.workspace = true
Expand Down
1 change: 1 addition & 0 deletions nexus/db-queries/src/db/datastore/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ mod support_bundle;
mod switch;
mod switch_interface;
mod switch_port;
mod target_release;
#[cfg(test)]
pub(crate) mod test_utils;
mod update;
Expand Down
Loading
Loading