Skip to content
Merged
13 changes: 12 additions & 1 deletion nexus/db-model/src/ipv6net.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,20 @@ use ipnetwork::IpNetwork;
use omicron_common::api::external;
use omicron_common::nexus_config::NUM_INITIAL_RESERVED_IP_ADDRESSES;
use rand::{rngs::StdRng, SeedableRng};
use serde::Deserialize;
use serde::Serialize;
use std::net::Ipv6Addr;

#[derive(Clone, Copy, Debug, PartialEq, AsExpression, FromSqlRow)]
#[derive(
Clone,
Copy,
Debug,
PartialEq,
AsExpression,
FromSqlRow,
Serialize,
Deserialize,
)]
#[diesel(sql_type = sql_types::Inet)]
pub struct Ipv6Net(pub external::Ipv6Net);

Expand Down
6 changes: 5 additions & 1 deletion nexus/db-model/src/l4_port_range.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,14 @@ use diesel::pg::Pg;
use diesel::serialize::{self, ToSql};
use diesel::sql_types;
use omicron_common::api::external;
use serde::Deserialize;
use serde::Serialize;

/// Newtype wrapper around [`external::L4PortRange`] so we can derive
/// diesel traits for it
#[derive(Clone, Copy, Debug, AsExpression, FromSqlRow)]
#[derive(
Clone, Copy, Debug, AsExpression, FromSqlRow, Serialize, Deserialize,
)]
#[diesel(sql_type = sql_types::Text)]
#[repr(transparent)]
pub struct L4PortRange(pub external::L4PortRange);
Expand Down
6 changes: 5 additions & 1 deletion nexus/db-model/src/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,14 @@ use db_macros::Resource;
use nexus_types::external_api::params;
use nexus_types::external_api::views;
use nexus_types::identity::Resource;
use serde::Deserialize;
use serde::Serialize;
use uuid::Uuid;

/// Describes a project within the database.
#[derive(Selectable, Queryable, Insertable, Debug, Resource)]
#[derive(
Selectable, Queryable, Insertable, Debug, Resource, Serialize, Deserialize,
)]
#[diesel(table_name = project)]
pub struct Project {
#[diesel(embed)]
Expand Down
6 changes: 5 additions & 1 deletion nexus/db-model/src/vni.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,12 @@ use diesel::serialize;
use diesel::serialize::ToSql;
use diesel::sql_types;
use omicron_common::api::external;
use serde::Deserialize;
use serde::Serialize;

#[derive(Clone, Debug, Copy, AsExpression, FromSqlRow)]
#[derive(
Clone, Debug, Copy, AsExpression, FromSqlRow, Serialize, Deserialize,
)]
#[diesel(sql_type = sql_types::Int4)]
pub struct Vni(pub external::Vni);

Expand Down
13 changes: 12 additions & 1 deletion nexus/db-model/src/vpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,20 @@ use nexus_types::external_api::params;
use nexus_types::external_api::views;
use nexus_types::identity::Resource;
use omicron_common::api::external;
use serde::Deserialize;
use serde::Serialize;
use uuid::Uuid;

#[derive(Queryable, Insertable, Clone, Debug, Selectable, Resource)]
#[derive(
Queryable,
Insertable,
Clone,
Debug,
Selectable,
Resource,
Serialize,
Deserialize,
)]
#[diesel(table_name = vpc)]
pub struct Vpc {
#[diesel(embed)]
Expand Down
29 changes: 21 additions & 8 deletions nexus/db-model/src/vpc_firewall_rule.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ use diesel::serialize::{self, ToSql};
use diesel::sql_types;
use nexus_types::identity::Resource;
use omicron_common::api::external;
use serde::Deserialize;
use serde::Serialize;
use std::io::Write;
use uuid::Uuid;

Expand All @@ -20,7 +22,7 @@ impl_enum_wrapper!(
#[diesel(postgres_type(name = "vpc_firewall_rule_status"))]
pub struct VpcFirewallRuleStatusEnum;

#[derive(Clone, Debug, AsExpression, FromSqlRow)]
#[derive(Clone, Debug, AsExpression, FromSqlRow, Serialize, Deserialize)]
#[diesel(sql_type = VpcFirewallRuleStatusEnum)]
pub struct VpcFirewallRuleStatus(pub external::VpcFirewallRuleStatus);

Expand All @@ -35,7 +37,7 @@ impl_enum_wrapper!(
#[diesel(postgres_type(name = "vpc_firewall_rule_direction"))]
pub struct VpcFirewallRuleDirectionEnum;

#[derive(Clone, Debug, AsExpression, FromSqlRow)]
#[derive(Clone, Debug, AsExpression, FromSqlRow, Serialize, Deserialize)]
#[diesel(sql_type = VpcFirewallRuleDirectionEnum)]
pub struct VpcFirewallRuleDirection(pub external::VpcFirewallRuleDirection);

Expand All @@ -50,7 +52,7 @@ impl_enum_wrapper!(
#[diesel(postgres_type(name = "vpc_firewall_rule_action"))]
pub struct VpcFirewallRuleActionEnum;

#[derive(Clone, Debug, AsExpression, FromSqlRow)]
#[derive(Clone, Debug, AsExpression, FromSqlRow, Serialize, Deserialize)]
#[diesel(sql_type = VpcFirewallRuleActionEnum)]
pub struct VpcFirewallRuleAction(pub external::VpcFirewallRuleAction);

Expand All @@ -65,7 +67,7 @@ impl_enum_wrapper!(
#[diesel(postgres_type(name = "vpc_firewall_rule_protocol"))]
pub struct VpcFirewallRuleProtocolEnum;

#[derive(Clone, Debug, AsExpression, FromSqlRow)]
#[derive(Clone, Debug, AsExpression, FromSqlRow, Serialize, Deserialize)]
#[diesel(sql_type = VpcFirewallRuleProtocolEnum)]
pub struct VpcFirewallRuleProtocol(pub external::VpcFirewallRuleProtocol);

Expand All @@ -78,7 +80,7 @@ NewtypeDeref! { () pub struct VpcFirewallRuleProtocol(external::VpcFirewallRuleP

/// Newtype wrapper around [`external::VpcFirewallRuleTarget`] so we can derive
/// diesel traits for it
#[derive(Clone, Debug, AsExpression, FromSqlRow)]
#[derive(Clone, Debug, AsExpression, FromSqlRow, Serialize, Deserialize)]
#[diesel(sql_type = sql_types::Text)]
#[repr(transparent)]
pub struct VpcFirewallRuleTarget(pub external::VpcFirewallRuleTarget);
Expand Down Expand Up @@ -113,7 +115,7 @@ where

/// Newtype wrapper around [`external::VpcFirewallRuleHostFilter`] so we can derive
/// diesel traits for it
#[derive(Clone, Debug, AsExpression, FromSqlRow)]
#[derive(Clone, Debug, AsExpression, FromSqlRow, Serialize, Deserialize)]
#[diesel(sql_type = sql_types::Text)]
#[repr(transparent)]
pub struct VpcFirewallRuleHostFilter(pub external::VpcFirewallRuleHostFilter);
Expand Down Expand Up @@ -148,7 +150,9 @@ where

/// Newtype wrapper around [`external::VpcFirewallRulePriority`] so we can derive
/// diesel traits for it
#[derive(Clone, Copy, Debug, AsExpression, FromSqlRow)]
#[derive(
Clone, Copy, Debug, AsExpression, FromSqlRow, Serialize, Deserialize,
)]
#[repr(transparent)]
#[diesel(sql_type = sql_types::Int4)]
pub struct VpcFirewallRulePriority(pub external::VpcFirewallRulePriority);
Expand Down Expand Up @@ -180,7 +184,16 @@ where
}
}

#[derive(Queryable, Insertable, Clone, Debug, Selectable, Resource)]
#[derive(
Queryable,
Insertable,
Clone,
Debug,
Selectable,
Resource,
Serialize,
Deserialize,
)]
#[diesel(table_name = vpc_firewall_rule)]
pub struct VpcFirewallRule {
#[diesel(embed)]
Expand Down
54 changes: 18 additions & 36 deletions nexus/src/app/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

//! Project APIs, contained within organizations

use crate::app::sagas;
use crate::authn;
use crate::authz;
use crate::context::OpContext;
use crate::db;
Expand All @@ -13,18 +15,17 @@ use crate::db::model::Name;
use crate::external_api::params;
use crate::external_api::shared;
use anyhow::Context;
use nexus_defaults as defaults;
use nexus_types::identity::Resource;
use omicron_common::api::external::CreateResult;
use omicron_common::api::external::DataPageParams;
use omicron_common::api::external::DeleteResult;
use omicron_common::api::external::Error;
use omicron_common::api::external::IdentityMetadataCreateParams;
use omicron_common::api::external::InternalContext;
use omicron_common::api::external::ListResultVec;
use omicron_common::api::external::LookupResult;
use omicron_common::api::external::NameOrId;
use omicron_common::api::external::UpdateResult;
use ref_cast::RefCast;
use std::sync::Arc;
use uuid::Uuid;

impl super::Nexus {
Expand Down Expand Up @@ -64,49 +65,30 @@ impl super::Nexus {
)),
}
}

pub async fn project_create(
&self,
self: &Arc<Self>,
opctx: &OpContext,
organization_lookup: &lookup::Organization<'_>,
new_project: &params::ProjectCreate,
) -> CreateResult<db::model::Project> {
let (.., authz_org) =
organization_lookup.lookup_for(authz::Action::CreateChild).await?;

// Create a project.
let db_project =
db::model::Project::new(authz_org.id(), new_project.clone());
let db_project = self
.db_datastore
.project_create(opctx, &authz_org, db_project)
.await?;
let project_lookup = LookupPath::new(opctx, &self.db_datastore)
.project_id(db_project.id());

// TODO: We probably want to have "project creation" and "default VPC
// creation" co-located within a saga for atomicity.
//
// Until then, we just perform the operations sequentially.

// Create a default VPC associated with the project.
let _ = self
.project_create_vpc(
opctx,
&project_lookup,
&params::VpcCreate {
identity: IdentityMetadataCreateParams {
name: "default".parse().unwrap(),
description: "Default VPC".to_string(),
},
ipv6_prefix: Some(defaults::random_vpc_ipv6_prefix()?),
// TODO-robustness this will need to be None if we decide to
// handle the logic around name and dns_name by making
// dns_name optional
dns_name: "default".parse().unwrap(),
},
let saga_params = sagas::project_create::Params {
serialized_authn: authn::saga::Serialized::for_opctx(opctx),
project_create: new_project.clone(),
authz_org,
};
let saga_outputs = self
.execute_saga::<sagas::project_create::SagaProjectCreate>(
saga_params,
)
.await?;

let db_project = saga_outputs
.lookup_node_output::<db::model::Project>("project")
.map_err(|e| Error::internal_error(&format!("{:#}", &e)))
.internal_context("looking up output from project create saga")?;
Ok(db_project)
}

Expand Down
6 changes: 6 additions & 0 deletions nexus/src/app/sagas/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,11 @@ pub mod disk_delete;
pub mod instance_create;
pub mod instance_delete;
pub mod instance_migrate;
pub mod project_create;
pub mod snapshot_create;
pub mod volume_delete;
pub mod volume_remove_rop;
pub mod vpc_create;

pub mod common_storage;

Expand Down Expand Up @@ -101,6 +103,9 @@ fn make_action_registry() -> ActionRegistry {
<instance_migrate::SagaInstanceMigrate as NexusSaga>::register_actions(
&mut registry,
);
<project_create::SagaProjectCreate as NexusSaga>::register_actions(
&mut registry,
);
<snapshot_create::SagaSnapshotCreate as NexusSaga>::register_actions(
&mut registry,
);
Expand All @@ -110,6 +115,7 @@ fn make_action_registry() -> ActionRegistry {
<volume_remove_rop::SagaVolumeRemoveROP as NexusSaga>::register_actions(
&mut registry,
);
<vpc_create::SagaVpcCreate as NexusSaga>::register_actions(&mut registry);

registry
}
Expand Down
Loading