From b48da000ea2c11941ecfab88120352d67981fd8a Mon Sep 17 00:00:00 2001 From: Kyle Simpson Date: Wed, 15 May 2024 16:57:32 +0100 Subject: [PATCH] We now have valid, sane, default system routes These update in response to VPC subnet changes. Now to plumb them into OPTE. --- nexus/db-model/src/vpc_route.rs | 2 +- nexus/db-queries/src/db/datastore/vpc.rs | 31 ++++++++++-- nexus/src/app/sagas/vpc_create.rs | 64 +----------------------- nexus/src/app/vpc_router.rs | 1 - 4 files changed, 29 insertions(+), 69 deletions(-) diff --git a/nexus/db-model/src/vpc_route.rs b/nexus/db-model/src/vpc_route.rs index 2c561325a53..dda7f0b7854 100644 --- a/nexus/db-model/src/vpc_route.rs +++ b/nexus/db-model/src/vpc_route.rs @@ -133,7 +133,7 @@ impl RouterRoute { system_router_id: Uuid, subnet: Name, ) -> Result { - let name = format!("subnet_{}", subnet).parse().map_err(|_| ())?; + let name = format!("sn-{}", subnet).parse().map_err(|_| ())?; Ok(Self::new( route_id, system_router_id, diff --git a/nexus/db-queries/src/db/datastore/vpc.rs b/nexus/db-queries/src/db/datastore/vpc.rs index 029f46e3c16..d200f676630 100644 --- a/nexus/db-queries/src/db/datastore/vpc.rs +++ b/nexus/db-queries/src/db/datastore/vpc.rs @@ -140,18 +140,26 @@ impl DataStore { // Unwrap safety: these are known valid CIDR blocks. let default_ips = [ - ("0.0.0.0/0".parse().unwrap(), *SERVICES_VPC_DEFAULT_V4_ROUTE_ID), - ("::/0".parse().unwrap(), *SERVICES_VPC_DEFAULT_V6_ROUTE_ID), + ( + "default-v4", + "0.0.0.0/0".parse().unwrap(), + *SERVICES_VPC_DEFAULT_V4_ROUTE_ID, + ), + ( + "default-v6", + "::/0".parse().unwrap(), + *SERVICES_VPC_DEFAULT_V6_ROUTE_ID, + ), ]; - for (default, uuid) in default_ips { + for (name, default, uuid) in default_ips { let route = RouterRoute::new( uuid, SERVICES_VPC.system_router_id, ExternalRouteKind::Default, nexus_types::external_api::params::RouterRouteCreate { identity: IdentityMetadataCreateParams { - name: "default".parse().unwrap(), + name: name.parse().unwrap(), description: "Default internet gateway route for Oxide Services" .to_string(), @@ -1036,6 +1044,18 @@ impl DataStore { ErrorHandler::NotFoundByResource(authz_router), ) })?; + + // All child routes are deleted. + use db::schema::router_route::dsl as rr; + let now = Utc::now(); + diesel::update(rr::router_route) + .filter(rr::time_deleted.is_null()) + .filter(rr::vpc_router_id.eq(authz_router.id())) + .set(rr::time_deleted.eq(now)) + .execute_async(&*self.pool_connection_authorized(opctx).await?) + .await + .map_err(|e| public_error_from_diesel(e, ErrorHandler::Server))?; + Ok(()) } @@ -1291,6 +1311,7 @@ impl DataStore { .transaction(&conn, |conn| { let log = log.clone(); async move { + use db::schema::router_route::dsl; use db::schema::vpc_subnet::dsl as subnet; use db::schema::vpc::dsl as vpc; @@ -1304,7 +1325,7 @@ impl DataStore { .await?; let valid_subnets: Vec = subnet::vpc_subnet - .filter(subnet::id.eq(vpc_id)) + .filter(subnet::vpc_id.eq(vpc_id)) .filter(subnet::time_deleted.is_null()) .select(VpcSubnet::as_select()) .load_async(&conn) diff --git a/nexus/src/app/sagas/vpc_create.rs b/nexus/src/app/sagas/vpc_create.rs index 72db2b49660..9f5f94c53c6 100644 --- a/nexus/src/app/sagas/vpc_create.rs +++ b/nexus/src/app/sagas/vpc_create.rs @@ -57,10 +57,6 @@ declare_saga_actions! { + svc_create_subnet - svc_create_subnet_undo } - VPC_CREATE_SUBNET_ROUTE -> "route" { - + svc_create_subnet_route - - svc_create_subnet_route_undo - } VPC_UPDATE_FIREWALL -> "firewall" { + svc_update_firewall - svc_update_firewall_undo @@ -97,11 +93,6 @@ pub fn create_dag( "GenerateDefaultV6RouteId", ACTION_GENERATE_ID.as_ref(), )); - builder.append(Node::action( - "default_subnet_route_id", - "GenerateDefaultV6RouteId", - ACTION_GENERATE_ID.as_ref(), - )); builder.append(Node::action( "default_subnet_id", "GenerateDefaultSubnetId", @@ -112,7 +103,6 @@ pub fn create_dag( builder.append(vpc_create_v4_route_action()); builder.append(vpc_create_v6_route_action()); builder.append(vpc_create_subnet_action()); - builder.append(vpc_create_subnet_route_action()); builder.append(vpc_update_firewall_action()); builder.append(vpc_notify_sleds_action()); @@ -246,7 +236,7 @@ async fn svc_create_v4_route( let default_route_id = sagactx.lookup::("default_v4_route_id")?; let default_route = "0.0.0.0/0".parse().expect("known-valid specifier for a default route"); - svc_create_route(sagactx, default_route_id, default_route, "default_v4") + svc_create_route(sagactx, default_route_id, default_route, "default-v4") .await } @@ -263,7 +253,7 @@ async fn svc_create_v6_route( let default_route_id = sagactx.lookup::("default_v6_route_id")?; let default_route = "::/0".parse().expect("known-valid specifier for a default route"); - svc_create_route(sagactx, default_route_id, default_route, "default_v6") + svc_create_route(sagactx, default_route_id, default_route, "default-v6") .await } @@ -427,56 +417,6 @@ async fn svc_create_subnet_undo( Ok(()) } -async fn svc_create_subnet_route( - sagactx: NexusActionContext, -) -> Result<(), ActionError> { - let osagactx = sagactx.user_data(); - let params = sagactx.saga_params::()?; - let opctx = crate::context::op_context_for_saga_action( - &sagactx, - ¶ms.serialized_authn, - ); - let system_router_id = sagactx.lookup::("system_router_id")?; - let authz_router = sagactx.lookup::("router")?; - let route_id = sagactx.lookup::("default_subnet_route_id")?; - let (_, db_subnet) = - sagactx.lookup::<(authz::VpcSubnet, db::model::VpcSubnet)>("subnet")?; - - let route = db::model::RouterRoute::for_subnet( - route_id, - system_router_id, - db_subnet.identity.name, - ) - .expect("default subnet name is short enough for route naming"); - - osagactx - .datastore() - .router_create_route(&opctx, &authz_router, route) - .await - .map_err(ActionError::action_failed)?; - Ok(()) -} - -async fn svc_create_subnet_route_undo( - sagactx: NexusActionContext, -) -> Result<(), anyhow::Error> { - let osagactx = sagactx.user_data(); - let params = sagactx.saga_params::()?; - let opctx = crate::context::op_context_for_saga_action( - &sagactx, - ¶ms.serialized_authn, - ); - let authz_router = sagactx.lookup::("router")?; - let route_id = sagactx.lookup::("default_subnet_route_id")?; - let authz_route = authz::RouterRoute::new( - authz_router, - route_id, - LookupType::ById(route_id), - ); - osagactx.datastore().router_delete_route(&opctx, &authz_route).await?; - Ok(()) -} - async fn svc_update_firewall( sagactx: NexusActionContext, ) -> Result, ActionError> { diff --git a/nexus/src/app/vpc_router.rs b/nexus/src/app/vpc_router.rs index 523a450bbd9..e65b2a86059 100644 --- a/nexus/src/app/vpc_router.rs +++ b/nexus/src/app/vpc_router.rs @@ -114,7 +114,6 @@ impl super::Nexus { .await } - // TODO: When a router is deleted all its routes should be deleted // TODO: When a router is deleted it should be unassociated w/ any subnets it may be associated with // or trigger an error pub(crate) async fn vpc_delete_router(