Skip to content

[1/5] User data export: DB models and queries #8399

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

Closed
wants to merge 1 commit into from
Closed
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
2 changes: 2 additions & 0 deletions nexus/db-model/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ mod typed_uuid;
mod unsigned;
mod upstairs_repair;
mod user_builtin;
mod user_data_export;
mod utilization;
mod virtual_provisioning_collection;
mod virtual_provisioning_resource;
Expand Down Expand Up @@ -236,6 +237,7 @@ pub use tuf_repo::*;
pub use typed_uuid::to_db_typed_uuid;
pub use upstairs_repair::*;
pub use user_builtin::*;
pub use user_data_export::*;
pub use utilization::*;
pub use v2p_mapping::*;
pub use virtual_provisioning_collection::*;
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(150, 0, 0);
pub const SCHEMA_VERSION: Version = Version::new(151, 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(151, "user-data-export"),
KnownVersion::new(150, "add-last-reconciliation-orphaned-datasets"),
KnownVersion::new(149, "bp-add-target-release-min-gen"),
KnownVersion::new(148, "clean-misplaced-m2s"),
Expand Down
152 changes: 152 additions & 0 deletions nexus/db-model/src/user_data_export.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
// 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::impl_enum_type;
use crate::SqlU16;
use crate::ipv6;
use crate::typed_uuid::DbTypedUuid;
use nexus_db_schema::schema::user_data_export;
use omicron_uuid_kinds::UserDataExportKind;
use omicron_uuid_kinds::UserDataExportUuid;
use omicron_uuid_kinds::VolumeKind;
use omicron_uuid_kinds::VolumeUuid;
use serde::Deserialize;
use serde::Serialize;
use std::net::SocketAddrV6;
use uuid::Uuid;

impl_enum_type!(
UserDataExportResourceTypeEnum:

#[derive(Copy, Clone, Debug, AsExpression, FromSqlRow, Serialize, Deserialize, PartialEq)]
pub enum UserDataExportResourceType;

// Enum values
Snapshot => b"snapshot"
Image => b"image"
);

// FromStr impl required for use with clap (aka omdb)
impl std::str::FromStr for UserDataExportResourceType {
type Err = String;

fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"snapshot" => Ok(UserDataExportResourceType::Snapshot),
"image" => Ok(UserDataExportResourceType::Image),
_ => Err(format!("unrecognized value {} for enum", s)),
}
}
}

impl UserDataExportResourceType {
pub fn to_string(&self) -> String {
String::from(match self {
UserDataExportResourceType::Snapshot => "snapshot",
UserDataExportResourceType::Image => "image",
})
}
}

/// A "user data export" object represents an attachment of a read-only volume
/// to a Pantry for the purpose of exporting data. As of this writing only
/// snapshots and images are able to be exported this way. Management of these
/// objects is done automatically by a background task.
///
/// Note that read-only volumes should never directly be constructed (read: be
/// passed to Volume::construct). Copies should be created so that the
/// appropriate reference counting for the read-only volume targets can be
/// maintained. The user data export object stores that copied Volume, among
/// other things.
#[derive(Queryable, Insertable, Selectable, Clone, Debug)]
#[diesel(table_name = user_data_export)]
pub struct UserDataExportRecord {
id: DbTypedUuid<UserDataExportKind>,
resource_type: UserDataExportResourceType,
resource_id: Uuid,
resource_deleted: bool,
pantry_ip: ipv6::Ipv6Addr,
pantry_port: SqlU16,
volume_id: DbTypedUuid<VolumeKind>,
}

impl UserDataExportRecord {
pub fn new(
id: UserDataExportUuid,
resource: UserDataExportResource,
pantry_address: SocketAddrV6,
volume_id: VolumeUuid,
) -> Self {
let (resource_type, resource_id) = match resource {
UserDataExportResource::Snapshot { id } => {
(UserDataExportResourceType::Snapshot, id)
}

UserDataExportResource::Image { id } => {
(UserDataExportResourceType::Image, id)
}
};

Self {
id: id.into(),
resource_type,
resource_id,
resource_deleted: false,
pantry_ip: ipv6::Ipv6Addr::from(*pantry_address.ip()),
pantry_port: SqlU16::from(pantry_address.port()),
volume_id: volume_id.into(),
}
}

pub fn id(&self) -> UserDataExportUuid {
self.id.into()
}

pub fn resource(&self) -> UserDataExportResource {
match self.resource_type {
UserDataExportResourceType::Snapshot => {
UserDataExportResource::Snapshot { id: self.resource_id }
}

UserDataExportResourceType::Image => {
UserDataExportResource::Image { id: self.resource_id }
}
}
}

pub fn deleted(&self) -> bool {
self.resource_deleted
}

pub fn pantry_address(&self) -> SocketAddrV6 {
SocketAddrV6::new(self.pantry_ip.into(), *self.pantry_port, 0, 0)
}

pub fn volume_id(&self) -> VolumeUuid {
self.volume_id.into()
}
}

#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq)]
pub enum UserDataExportResource {
Snapshot { id: Uuid },

Image { id: Uuid },
}

impl UserDataExportResource {
pub fn type_string(&self) -> String {
String::from(match self {
UserDataExportResource::Snapshot { .. } => "snapshot",
UserDataExportResource::Image { .. } => "image",
})
}

pub fn id(&self) -> Uuid {
match self {
UserDataExportResource::Snapshot { id } => *id,
UserDataExportResource::Image { id } => *id,
}
}
}
2 changes: 2 additions & 0 deletions nexus/db-queries/src/db/datastore/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ mod target_release;
#[cfg(test)]
pub(crate) mod test_utils;
mod update;
mod user_data_export;
mod utilization;
mod v2p_mapping;
mod virtual_provisioning_collection;
Expand Down Expand Up @@ -135,6 +136,7 @@ pub use sled::SledTransition;
pub use sled::TransitionError;
pub use support_bundle::SupportBundleExpungementReport;
pub use switch_port::SwitchPortSettingsCombinedResult;
pub use user_data_export::*;
pub use virtual_provisioning_collection::StorageType;
pub use vmm::VmmStateUpdateResult;
pub use volume::*;
Expand Down
Loading
Loading