From e8b6dd1dc4e7abb39276ad347bdf1ac08171862d Mon Sep 17 00:00:00 2001 From: Kyle Simpson Date: Mon, 22 Jan 2024 18:33:01 +0000 Subject: [PATCH] Add floating IP check to project delete (#4862) The main floating IP PR missed the check in `project_delete` for any existing child floating IP objects. This commit adds in this check so that a project cannot be deleted while any FIPs remain (matching other project-scoped resources), as well as a matching integration test. Closes #4854. --- nexus/db-queries/src/db/datastore/project.rs | 2 ++ nexus/tests/integration_tests/projects.rs | 34 ++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/nexus/db-queries/src/db/datastore/project.rs b/nexus/db-queries/src/db/datastore/project.rs index e3927fdfc1..08647b421e 100644 --- a/nexus/db-queries/src/db/datastore/project.rs +++ b/nexus/db-queries/src/db/datastore/project.rs @@ -221,6 +221,7 @@ impl DataStore { generate_fn_to_ensure_none_in_project!(instance, name, String); generate_fn_to_ensure_none_in_project!(disk, name, String); + generate_fn_to_ensure_none_in_project!(floating_ip, name, String); generate_fn_to_ensure_none_in_project!(project_image, name, String); generate_fn_to_ensure_none_in_project!(snapshot, name, String); generate_fn_to_ensure_none_in_project!(vpc, name, String); @@ -237,6 +238,7 @@ impl DataStore { // Verify that child resources do not exist. self.ensure_no_instances_in_project(opctx, authz_project).await?; self.ensure_no_disks_in_project(opctx, authz_project).await?; + self.ensure_no_floating_ips_in_project(opctx, authz_project).await?; self.ensure_no_project_images_in_project(opctx, authz_project).await?; self.ensure_no_snapshots_in_project(opctx, authz_project).await?; self.ensure_no_vpcs_in_project(opctx, authz_project).await?; diff --git a/nexus/tests/integration_tests/projects.rs b/nexus/tests/integration_tests/projects.rs index d9d6ceef5b..60195e5902 100644 --- a/nexus/tests/integration_tests/projects.rs +++ b/nexus/tests/integration_tests/projects.rs @@ -9,6 +9,7 @@ use http::StatusCode; use nexus_test_utils::http_testing::AuthnMode; use nexus_test_utils::http_testing::NexusRequest; use nexus_test_utils::http_testing::RequestBuilder; +use nexus_test_utils::resource_helpers::create_floating_ip; use nexus_test_utils::resource_helpers::{ create_default_ip_pool, create_disk, create_project, create_vpc, object_create, project_get, projects_list, DiskTest, @@ -209,6 +210,39 @@ async fn test_project_deletion_with_disk(cptestctx: &ControlPlaneTestContext) { delete_project(&url, &client).await; } +#[nexus_test] +async fn test_project_deletion_with_floating_ip( + cptestctx: &ControlPlaneTestContext, +) { + let client = &cptestctx.external_client; + + let _test = DiskTest::new(&cptestctx).await; + + // Create a project that we'll use for testing. + let name = "springfield-squidport"; + let url = format!("/v1/projects/{}", name); + + create_default_ip_pool(&client).await; + + create_project(&client, &name).await; + delete_project_default_subnet(&name, &client).await; + delete_project_default_vpc(&name, &client).await; + let fip = create_floating_ip(&client, "my-fip", &name, None, None).await; + assert_eq!( + "project to be deleted contains a floating ip: my-fip", + delete_project_expect_fail(&url, &client).await, + ); + let disk_url = + super::external_ips::get_floating_ip_by_id_url(&fip.identity.id); + NexusRequest::object_delete(&client, &disk_url) + .authn_as(AuthnMode::PrivilegedUser) + .execute() + .await + .expect("failed to delete floating IP"); + + delete_project(&url, &client).await; +} + #[nexus_test] async fn test_project_deletion_with_image(cptestctx: &ControlPlaneTestContext) { let client = &cptestctx.external_client;