Skip to content
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

[api][nexus] Migrate DB-specific types into Nexus, away from API #188

Merged
merged 16 commits into from
Aug 6, 2021
Merged
17 changes: 3 additions & 14 deletions omicron-common/src/api/external/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -459,7 +459,7 @@ impl Display for ResourceType {

pub async fn to_list<T, U>(object_stream: ObjectStream<T>) -> Vec<U>
where
U: From<T>,
T: Into<U>,
{
object_stream
.filter(|maybe_object| ready(maybe_object.is_ok()))
Expand Down Expand Up @@ -728,19 +728,6 @@ pub struct InstanceView {
pub runtime: InstanceRuntimeStateView,
}

impl From<crate::api::internal::nexus::Instance> for InstanceView {
fn from(instance: crate::api::internal::nexus::Instance) -> Self {
InstanceView {
identity: instance.identity.clone(),
project_id: instance.project_id,
ncpus: instance.ncpus,
memory: instance.memory,
hostname: instance.hostname.clone(),
runtime: instance.runtime.into(),
}
}
}

/**
* Create-time parameters for an [`Instance`]
*/
Expand Down Expand Up @@ -788,6 +775,7 @@ pub struct DiskView {
pub device_path: String,
}

/*
impl From<crate::api::internal::nexus::Disk> for DiskView {
fn from(disk: crate::api::internal::nexus::Disk) -> Self {
/*
Expand All @@ -805,6 +793,7 @@ impl From<crate::api::internal::nexus::Disk> for DiskView {
}
}
}
*/

/**
* State of a Disk (primarily: attached or not)
Expand Down
38 changes: 6 additions & 32 deletions omicron-common/src/api/internal/nexus.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
//! APIs exposed by Nexus.

use crate::api::external::{
ByteCount, DiskState, Generation, IdentityMetadata, InstanceCpuCount,
InstanceState,
DiskState, Generation, IdentityMetadata, InstanceState,
};
use chrono::{DateTime, Utc};
use schemars::JsonSchema;
Expand All @@ -11,6 +10,9 @@ use std::net::SocketAddr;
use std::time::Duration;
use uuid::Uuid;

// TODO: Do a pass of this file. If stuff was moved to a DB repr, it's not
// needed here.

pub struct Rack {
pub identity: IdentityMetadata,
}
Expand All @@ -26,6 +28,7 @@ pub struct Project {
pub identity: IdentityMetadata,
}

/*
/// A Disk (network block device).
#[derive(Clone, Debug)]
pub struct Disk {
Expand All @@ -41,6 +44,7 @@ pub struct Disk {
/// runtime state of the Disk
pub runtime: DiskRuntimeState,
}
*/

/// Runtime state of the Disk, which includes its attach state and some minimal
/// metadata
Expand All @@ -54,28 +58,6 @@ pub struct DiskRuntimeState {
pub time_updated: DateTime<Utc>,
}

/// An Instance (VM).
#[derive(Clone, Debug)]
pub struct Instance {
/// common identifying metadata
pub identity: IdentityMetadata,

/// id for the project containing this Instance
pub project_id: Uuid,

/// number of CPUs allocated for this Instance
pub ncpus: InstanceCpuCount,
/// memory allocated for this Instance
pub memory: ByteCount,
/// RFC1035-compliant hostname for the Instance.
// TODO-cleanup different type?
pub hostname: String,

/// state owned by the data plane
pub runtime: InstanceRuntimeState,
// TODO-completeness: add disks, network, tags, metrics
}

/// Runtime state of the Instance, including the actual running state and minimal
/// metadata
///
Expand Down Expand Up @@ -129,11 +111,3 @@ pub struct OximeterInfo {
/// The address on which this oximeter instance listens for requests
pub address: SocketAddr,
}

/// An assignment of an Oximeter instance to a metric producer for collection.
// TODO: Goes to storage
#[derive(Debug, Clone, Copy, JsonSchema, Serialize, Deserialize)]
pub struct OximeterAssignment {
pub oximeter_id: Uuid,
pub producer_id: Uuid,
}
5 changes: 4 additions & 1 deletion omicron-common/src/api/internal/sled_agent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,15 @@ impl DiskStateRequested {
}
}

/// Runtime state of an instance.
pub type InstanceRuntimeState = internal::nexus::InstanceRuntimeState;

/// Sent to a sled agent to establish the runtime state of an Instance
#[derive(Serialize, Deserialize, JsonSchema)]
pub struct InstanceEnsureBody {
/// Last runtime state of the Instance known to Nexus (used if the agent
/// has never seen this Instance before).
pub initial_runtime: internal::nexus::InstanceRuntimeState,
pub initial_runtime: InstanceRuntimeState,
/// requested runtime state of the Instance
pub target: InstanceRuntimeStateRequested,
}
Expand Down
169 changes: 0 additions & 169 deletions omicron-common/src/model_db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,37 +49,22 @@
* TODO-coverage tests for these FromSql and ToSql implementations
*/

use std::net::{IpAddr, SocketAddr};
use std::time::Duration;

use super::db::sql_row_value;
use crate::api::external::ByteCount;
use crate::api::external::DiskAttachment;
use crate::api::external::DiskState;
use crate::api::external::Error;
use crate::api::external::Generation;
use crate::api::external::IdentityMetadata;
use crate::api::external::InstanceCpuCount;
use crate::api::external::InstanceState;
use crate::api::external::MacAddr;
use crate::api::external::Name;
use crate::api::external::NetworkInterface;
use crate::api::external::Vpc;
use crate::api::external::VpcSubnet;
use crate::api::external::{Ipv4Net, Ipv6Net};
use crate::api::internal::nexus::Disk;
use crate::api::internal::nexus::DiskRuntimeState;
use crate::api::internal::nexus::Instance;
use crate::api::internal::nexus::InstanceRuntimeState;
use crate::api::internal::nexus::OximeterAssignment;
use crate::api::internal::nexus::OximeterInfo;
use crate::api::internal::nexus::ProducerEndpoint;
use crate::api::internal::nexus::Project;
use crate::bail_unless;
use chrono::DateTime;
use chrono::Utc;
use std::convert::TryFrom;
use uuid::Uuid;

/*
* FromSql/ToSql impls used for simple Rust types
Expand Down Expand Up @@ -280,160 +265,6 @@ impl TryFrom<&tokio_postgres::Row> for IdentityMetadata {
}
}

impl TryFrom<&tokio_postgres::Row> for InstanceState {
type Error = Error;

fn try_from(value: &tokio_postgres::Row) -> Result<Self, Self::Error> {
let variant: &str = sql_row_value(value, "instance_state")?;
InstanceState::try_from(variant)
.map_err(|err| Error::InternalError { message: err })
}
}

/// Load an [`Project`] from a whole row of the "Project" table.
impl TryFrom<&tokio_postgres::Row> for Project {
type Error = Error;

fn try_from(value: &tokio_postgres::Row) -> Result<Self, Self::Error> {
Ok(Project { identity: IdentityMetadata::try_from(value)? })
}
}

/// Load an [`Instance`] from a whole row of the "Instance" table.
impl TryFrom<&tokio_postgres::Row> for Instance {
type Error = Error;

fn try_from(value: &tokio_postgres::Row) -> Result<Self, Self::Error> {
Ok(Instance {
identity: IdentityMetadata::try_from(value)?,
project_id: sql_row_value(value, "project_id")?,
ncpus: sql_row_value(value, "ncpus")?,
memory: sql_row_value(value, "memory")?,
hostname: sql_row_value(value, "hostname")?,
runtime: InstanceRuntimeState::try_from(value)?,
})
}
}

/// Load an [`InstanceRuntimeState`] from a row of the "Instance" table,
/// using the "instance_state", "active_server_id", "state_generation", and
/// "time_state_updated" columns.
impl TryFrom<&tokio_postgres::Row> for InstanceRuntimeState {
type Error = Error;

fn try_from(value: &tokio_postgres::Row) -> Result<Self, Self::Error> {
Ok(InstanceRuntimeState {
run_state: InstanceState::try_from(value)?,
sled_uuid: sql_row_value(value, "active_server_id")?,
gen: sql_row_value(value, "state_generation")?,
time_updated: sql_row_value(value, "time_state_updated")?,
})
}
}

/// Load an [`Disk`] from a row of the "Disk" table.
impl TryFrom<&tokio_postgres::Row> for Disk {
type Error = Error;

fn try_from(value: &tokio_postgres::Row) -> Result<Self, Self::Error> {
Ok(Disk {
identity: IdentityMetadata::try_from(value)?,
project_id: sql_row_value(value, "project_id")?,
create_snapshot_id: sql_row_value(value, "origin_snapshot")?,
size: sql_row_value(value, "size_bytes")?,
runtime: DiskRuntimeState::try_from(value)?,
})
}
}

/// Load an [`DiskAttachment`] from a database row containing those columns
/// of the Disk table that describe the attachment: "id", "name", "disk_state",
/// "attach_instance_id"
impl TryFrom<&tokio_postgres::Row> for DiskAttachment {
type Error = Error;

fn try_from(value: &tokio_postgres::Row) -> Result<Self, Self::Error> {
Ok(DiskAttachment {
instance_id: sql_row_value(value, "attach_instance_id")?,
disk_id: sql_row_value(value, "id")?,
disk_name: sql_row_value(value, "name")?,
disk_state: DiskState::try_from(value)?,
})
}
}

/// Load an [`DiskRuntimeState`'] from a row from the Disk table, using the
/// columns needed for [`DiskState`], plus "state_generation" and
/// "time_state_updated".
impl TryFrom<&tokio_postgres::Row> for DiskRuntimeState {
type Error = Error;

fn try_from(value: &tokio_postgres::Row) -> Result<Self, Self::Error> {
Ok(DiskRuntimeState {
disk_state: DiskState::try_from(value)?,
gen: sql_row_value(value, "state_generation")?,
time_updated: sql_row_value(value, "time_state_updated")?,
})
}
}

/// Load an [`DiskState`] from a row from the Disk table, using the columns
/// "disk_state" and "attach_instance_id".
impl TryFrom<&tokio_postgres::Row> for DiskState {
type Error = Error;

fn try_from(value: &tokio_postgres::Row) -> Result<Self, Self::Error> {
let disk_state_str: &str = sql_row_value(value, "disk_state")?;
let instance_uuid: Option<Uuid> =
sql_row_value(value, "attach_instance_id")?;
DiskState::try_from((disk_state_str, instance_uuid))
.map_err(|e| Error::internal_error(&e))
}
}

/// Load a [`ProducerEndpoint`] from a row in the `MetricProducer` table, using
/// the columns "id", "ip", "port", "interval", and "route"
impl TryFrom<&tokio_postgres::Row> for ProducerEndpoint {
type Error = Error;

fn try_from(value: &tokio_postgres::Row) -> Result<Self, Self::Error> {
let id: Uuid = sql_row_value(value, "id")?;
let ip: IpAddr = sql_row_value(value, "ip")?;
let port: i32 = sql_row_value(value, "port")?;
let address = SocketAddr::new(ip, port as _);
let base_route: String = sql_row_value(value, "route")?;
let interval =
Duration::from_secs_f64(sql_row_value(value, "interval")?);
Ok(Self { id, address, base_route, interval })
}
}

/// Load an [`OximeterInfo`] from a row in the `Oximeter` table, using the
/// columns "id", "ip", and "port".
impl TryFrom<&tokio_postgres::Row> for OximeterInfo {
type Error = Error;

fn try_from(value: &tokio_postgres::Row) -> Result<Self, Self::Error> {
let collector_id: Uuid = sql_row_value(value, "id")?;
let ip: IpAddr = sql_row_value(value, "ip")?;
let port: i32 = sql_row_value(value, "port")?;
let address = SocketAddr::new(ip, port as _);
Ok(Self { collector_id, address })
}
}

/// Load an [`OximeterAssignment`] from a row in the `OximeterAssignment`
/// table, using the columns "oximeter_id" and "producer_id"
impl TryFrom<&tokio_postgres::Row> for OximeterAssignment {
type Error = Error;

fn try_from(value: &tokio_postgres::Row) -> Result<Self, Self::Error> {
let oximeter_id: Uuid = sql_row_value(value, "oximeter_id")?;
let producer_id: Uuid = sql_row_value(value, "producer_id")?;
Ok(Self { oximeter_id, producer_id })
}
}

/// Load an [`Vpc`] from a row in the `Vpc` table.
impl TryFrom<&tokio_postgres::Row> for Vpc {
type Error = Error;
Expand Down
11 changes: 5 additions & 6 deletions omicron-common/src/sled_agent_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,12 @@
* generated by the server.
*/

use crate::api;
use crate::api::external::Error;
use crate::api::internal::nexus::DiskRuntimeState;
use crate::api::internal::nexus::InstanceRuntimeState;
use crate::api::internal::sled_agent::DiskEnsureBody;
use crate::api::internal::sled_agent::DiskStateRequested;
use crate::api::internal::sled_agent::InstanceEnsureBody;
use crate::api::internal::sled_agent::InstanceRuntimeStateRequested;
use crate::http_client::HttpClient;
use async_trait::async_trait;
use http::Method;
Expand Down Expand Up @@ -54,9 +53,9 @@ impl Client {
pub async fn instance_ensure(
self: &Arc<Self>,
instance_id: Uuid,
initial_runtime: InstanceRuntimeState,
target: InstanceRuntimeStateRequested,
) -> Result<InstanceRuntimeState, Error> {
initial_runtime: api::internal::sled_agent::InstanceRuntimeState,
target: api::internal::sled_agent::InstanceRuntimeStateRequested,
) -> Result<api::internal::sled_agent::InstanceRuntimeState, Error> {
let path = format!("/instances/{}", instance_id);
let body = Body::from(
serde_json::to_string(&InstanceEnsureBody {
Expand All @@ -71,7 +70,7 @@ impl Client {
assert!(response.status().is_success());
let value = self
.client
.read_json::<InstanceRuntimeState>(
.read_json::<api::internal::sled_agent::InstanceRuntimeState>(
&self.client.error_message_base(&Method::PUT, path.as_str()),
&mut response,
)
Expand Down
Loading