Skip to content

Commit

Permalink
Merge branch 'main' into dap/initial-setup
Browse files Browse the repository at this point in the history
  • Loading branch information
davepacheco committed Apr 28, 2023
2 parents 5181a64 + e034cd6 commit 2317079
Show file tree
Hide file tree
Showing 20 changed files with 693 additions and 667 deletions.
9 changes: 7 additions & 2 deletions Cargo.lock

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

139 changes: 29 additions & 110 deletions common/src/api/external/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,7 @@ use api_identity::ObjectIdentity;
use chrono::DateTime;
use chrono::Utc;
pub use dropshot::PaginationOrder;
use futures::future::ready;
use futures::stream::BoxStream;
use futures::stream::StreamExt;
use parse_display::Display;
use parse_display::FromStr;
use rand::thread_rng;
Expand Down Expand Up @@ -492,18 +490,19 @@ impl JsonSchema for RoleName {
}
}

/// A count of bytes, typically used either for memory or storage capacity
///
/// The maximum supported byte count is [`i64::MAX`]. This makes it somewhat
/// inconvenient to define constructors: a u32 constructor can be infallible, but
/// an i64 constructor can fail (if the value is negative) and a u64 constructor
/// can fail (if the value is larger than i64::MAX). We provide all of these for
/// consumers' convenience.
// TODO-cleanup This could benefit from a more complete implementation.
/// Byte count to express memory or storage capacity.
//
// The maximum supported byte count is [`i64::MAX`]. This makes it somewhat
// inconvenient to define constructors: a u32 constructor can be infallible,
// but an i64 constructor can fail (if the value is negative) and a u64
// constructor can fail (if the value is larger than i64::MAX). We provide
// all of these for consumers' convenience.
//
// The maximum byte count of i64::MAX comes from the fact that this is stored
// in the database as an i64. Constraining it here ensures that we can't fail
// to serialize the value.
//
// The maximum byte count of i64::MAX comes from the fact that this is stored in
// the database as an i64. Constraining it here ensures that we can't fail to
// serialize the value.
// TODO: custom JsonSchema and Deserialize impls to enforce i64::MAX limit
#[derive(Copy, Clone, Debug, Deserialize, Serialize, JsonSchema, PartialEq)]
pub struct ByteCount(u64);

Expand Down Expand Up @@ -728,17 +727,6 @@ pub enum ResourceType {
Zpool,
}

pub async fn to_list<T, U>(object_stream: ObjectStream<T>) -> Vec<U>
where
T: Into<U>,
{
object_stream
.filter(|maybe_object| ready(maybe_object.is_ok()))
.map(|maybe_object| maybe_object.unwrap().into())
.collect::<Vec<U>>()
.await
}

// IDENTITY METADATA

/// Identity-related metadata that's included in nearly all public API objects
Expand Down Expand Up @@ -903,7 +891,7 @@ impl From<&InstanceCpuCount> for i64 {
}
}

/// Client view of an [`InstanceRuntimeState`]
/// The state of an `Instance`
#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema)]
pub struct InstanceRuntimeState {
pub run_state: InstanceState,
Expand All @@ -921,7 +909,7 @@ impl From<crate::api::internal::nexus::InstanceRuntimeState>
}
}

/// Client view of an [`Instance`]
/// View of an Instance
#[derive(ObjectIdentity, Clone, Debug, Deserialize, Serialize, JsonSchema)]
pub struct Instance {
// TODO is flattening here the intent in RFD 4?
Expand All @@ -944,7 +932,7 @@ pub struct Instance {

// DISKS

/// Client view of a [`Disk`]
/// View of a Disk
#[derive(ObjectIdentity, Clone, Debug, Deserialize, Serialize, JsonSchema)]
pub struct Disk {
#[serde(flatten)]
Expand All @@ -958,7 +946,7 @@ pub struct Disk {
pub device_path: String,
}

/// State of a Disk (primarily: attached or not)
/// State of a Disk
#[derive(
Clone,
Debug,
Expand Down Expand Up @@ -1079,77 +1067,6 @@ impl DiskState {
}
}

// Sagas
//
// These are currently only intended for observability by developers. We will
// eventually want to flesh this out into something more observable for end
// users.
#[derive(Clone, Debug, Serialize, JsonSchema)]
pub struct Saga {
pub id: Uuid,
pub state: SagaState,
}

impl From<steno::SagaView> for Saga {
fn from(s: steno::SagaView) -> Self {
Saga { id: Uuid::from(s.id), state: SagaState::from(s.state) }
}
}

#[derive(Clone, Debug, Serialize, JsonSchema)]
#[serde(tag = "state", rename_all = "snake_case")]
pub enum SagaState {
Running,
Succeeded,
Failed { error_node_name: steno::NodeName, error_info: SagaErrorInfo },
}

#[derive(Clone, Debug, Serialize, JsonSchema)]
#[serde(tag = "error", rename_all = "snake_case")]
pub enum SagaErrorInfo {
ActionFailed { source_error: serde_json::Value },
DeserializeFailed { message: String },
InjectedError,
SerializeFailed { message: String },
SubsagaCreateFailed { message: String },
}

impl From<steno::SagaStateView> for SagaState {
fn from(st: steno::SagaStateView) -> Self {
match st {
steno::SagaStateView::Ready { .. } => SagaState::Running,
steno::SagaStateView::Running { .. } => SagaState::Running,
steno::SagaStateView::Done {
result: steno::SagaResult { kind: Ok(_), .. },
..
} => SagaState::Succeeded,
steno::SagaStateView::Done {
result: steno::SagaResult { kind: Err(e), .. },
..
} => SagaState::Failed {
error_node_name: e.error_node_name,
error_info: match e.error_source {
steno::ActionError::ActionFailed { source_error } => {
SagaErrorInfo::ActionFailed { source_error }
}
steno::ActionError::DeserializeFailed { message } => {
SagaErrorInfo::DeserializeFailed { message }
}
steno::ActionError::InjectedError => {
SagaErrorInfo::InjectedError
}
steno::ActionError::SerializeFailed { message } => {
SagaErrorInfo::SerializeFailed { message }
}
steno::ActionError::SubsagaCreateFailed { message } => {
SagaErrorInfo::SubsagaCreateFailed { message }
}
},
},
}
}
}

/// An `Ipv4Net` represents a IPv4 subnetwork, including the address and network mask.
#[derive(Clone, Copy, Debug, Deserialize, Hash, PartialEq, Eq, Serialize)]
pub struct Ipv4Net(pub ipnetwork::Ipv4Network);
Expand Down Expand Up @@ -1530,8 +1447,8 @@ pub enum RouteTarget {
/// destination of that traffic.
///
/// When traffic is to be sent to a destination that is within a given
/// `RouteDestination`, the corresponding [`RouterRoute`] applies, and traffic
/// will be forward to the [`RouteTarget`] for that rule.
/// `RouteDestination`, the corresponding `RouterRoute` applies, and traffic
/// will be forward to the `RouteTarget` for that rule.
#[derive(
Clone,
Debug,
Expand All @@ -1555,18 +1472,20 @@ pub enum RouteDestination {
Subnet(Name),
}

/// The classification of a [`RouterRoute`] as defined by the system.
/// The kind of a `RouterRoute`
///
/// The kind determines certain attributes such as if the route is modifiable
/// and describes how or where the route was created.
///
/// See [RFD-21](https://rfd.shared.oxide.computer/rfd/0021#concept-router) for more context
//
// See [RFD-21](https://rfd.shared.oxide.computer/rfd/0021#concept-router) for more context
#[derive(
Clone, Copy, Debug, PartialEq, Deserialize, Serialize, Display, JsonSchema,
)]
#[display("{}")]
#[serde(rename_all = "snake_case")]
pub enum RouterRouteKind {
/// Determines the default destination of traffic, such as whether it goes to the internet or not.
/// Determines the default destination of traffic, such as whether it goes
/// to the internet or not.
///
/// `Destination: An Internet Gateway`
/// `Modifiable: true`
Expand All @@ -1581,22 +1500,22 @@ pub enum RouterRouteKind {
/// `Destination: A different VPC`
/// `Modifiable: false`
VpcPeering,
/// Created by a user
/// See [`RouteTarget`]
/// Created by a user; see `RouteTarget`
///
/// `Destination: User defined`
/// `Modifiable: true`
Custom,
}

/// A route defines a rule that governs where traffic should be sent based on its destination.
/// A route defines a rule that governs where traffic should be sent based on
/// its destination.
#[derive(ObjectIdentity, Clone, Debug, Deserialize, Serialize, JsonSchema)]
pub struct RouterRoute {
/// common identifying metadata
#[serde(flatten)]
pub identity: IdentityMetadata,

/// The VPC Router to which the route belongs.
/// The ID of the VPC Router to which the route belongs
pub vpc_router_id: Uuid,

/// Describes the kind of router. Set at creation. `read-only`
Expand Down Expand Up @@ -1725,7 +1644,7 @@ pub enum VpcFirewallRuleAction {
Deny,
}

/// A `VpcFirewallRuleTarget` is used to specify the set of [`Instance`]s to
/// A `VpcFirewallRuleTarget` is used to specify the set of `Instance`s to
/// which a firewall rule applies.
#[derive(
Clone,
Expand Down
1 change: 1 addition & 0 deletions nexus-client/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ license = "MPL-2.0"

[dependencies]
chrono.workspace = true
futures.workspace = true
omicron-common.workspace = true
progenitor.workspace = true
regress.workspace = true
Expand Down
9 changes: 4 additions & 5 deletions nexus/src/app/saga.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ use anyhow::Context;
use futures::future::BoxFuture;
use futures::StreamExt;
use nexus_db_queries::context::OpContext;
use omicron_common::api::external;
use omicron_common::api::external::DataPageParams;
use omicron_common::api::external::Error;
use omicron_common::api::external::ListResult;
Expand Down Expand Up @@ -61,7 +60,7 @@ impl super::Nexus {
&self,
opctx: &OpContext,
pagparams: &DataPageParams<'_, Uuid>,
) -> ListResult<external::Saga> {
) -> ListResult<nexus_types::internal_api::views::Saga> {
// The endpoint we're serving only supports `ScanById`, which only
// supports an ascending scan.
bail_unless!(
Expand All @@ -74,7 +73,7 @@ impl super::Nexus {
.saga_list(marker, pagparams.limit)
.await
.into_iter()
.map(external::Saga::from)
.map(nexus_types::internal_api::views::Saga::from)
.map(Ok);
Ok(futures::stream::iter(saga_list).boxed())
}
Expand All @@ -83,12 +82,12 @@ impl super::Nexus {
&self,
opctx: &OpContext,
id: Uuid,
) -> LookupResult<external::Saga> {
) -> LookupResult<nexus_types::internal_api::views::Saga> {
opctx.authorize(authz::Action::Read, &authz::FLEET).await?;
self.sec_client
.saga_get(SagaId::from(id))
.await
.map(external::Saga::from)
.map(nexus_types::internal_api::views::Saga::from)
.map(Ok)
.map_err(|_: ()| {
Error::not_found_by_id(ResourceType::SagaDbg, &id)
Expand Down
4 changes: 2 additions & 2 deletions nexus/src/external_api/console_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,7 @@ pub async fn login_saml_begin(
apictx.external_latencies.instrument_dropshot_handler(&rqctx, handler).await
}

/// Authenticate a user (i.e., log in) via SAML
/// Authenticate a user via SAML
#[endpoint {
method = POST,
path = "/login/{silo_name}/saml/{provider_name}",
Expand Down Expand Up @@ -393,7 +393,7 @@ pub struct LoginPathParam {
pub silo_name: crate::db::model::Name,
}

/// Authenticate a user (i.e., log in) via username and password
/// Authenticate a user via username and password
#[endpoint {
method = POST,
path = "/login/{silo_name}/local",
Expand Down
Loading

0 comments on commit 2317079

Please sign in to comment.