diff options
author | Øyvind Grønnesby <oyving@verizonmedia.com> | 2021-03-02 13:09:01 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-03-02 13:09:01 +0100 |
commit | bfd326596ca51f9a0725cd8595ab67dcead3aeb7 (patch) | |
tree | 2540fbfd5f0e951366ac33e110daca5864d43bfa | |
parent | e1a6e35483ed567584b4fbc7e65e4c9e01b30ef1 (diff) | |
parent | 11eb06c0818e97a8eff09029cbbe0ea26fbfa06f (diff) |
Merge pull request #16735 from vespa-engine/olaa/delete-secret-store
Delete tenant secret store
6 files changed, 60 insertions, 4 deletions
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/secrets/NoopTenantSecretService.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/secrets/NoopTenantSecretService.java index 9f273723c9c..f0d172934ba 100644 --- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/secrets/NoopTenantSecretService.java +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/secrets/NoopTenantSecretService.java @@ -11,4 +11,7 @@ public class NoopTenantSecretService implements TenantSecretService { @Override public void addSecretStore(TenantName tenant, TenantSecretStore tenantSecretStore, String externalId) {} + @Override + public void deleteSecretStore(TenantName tenant, TenantSecretStore tenantSecretStore) {} + } diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/secrets/TenantSecretService.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/secrets/TenantSecretService.java index bac5a012f79..c8320b9a1cc 100644 --- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/secrets/TenantSecretService.java +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/secrets/TenantSecretService.java @@ -10,4 +10,6 @@ public interface TenantSecretService { void addSecretStore(TenantName tenant, TenantSecretStore tenantSecretStore, String externalId); + void deleteSecretStore(TenantName tenant, TenantSecretStore tenantSecretStore); + } diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/LockedTenant.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/LockedTenant.java index 519c08b66f5..22fa25fc711 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/LockedTenant.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/LockedTenant.java @@ -167,6 +167,12 @@ public abstract class LockedTenant { secretStores.add(tenantSecretStore); return new Cloud(name, createdAt, lastLoginInfo, creator, developerKeys, info, secretStores); } + + public Cloud withoutSecretStore(TenantSecretStore tenantSecretStore) { + ArrayList<TenantSecretStore> secretStores = new ArrayList<>(tenantSecretStores); + secretStores.remove(tenantSecretStore); + return new Cloud(name, createdAt, lastLoginInfo, creator, developerKeys, info, secretStores); + } } } diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java index 3649bc2ac80..23f62ee3cf5 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java @@ -313,6 +313,7 @@ public class ApplicationApiHandler extends LoggingRequestHandler { private HttpResponse handleDELETE(Path path, HttpRequest request) { if (path.matches("/application/v4/tenant/{tenant}")) return deleteTenant(path.get("tenant"), request); if (path.matches("/application/v4/tenant/{tenant}/key")) return removeDeveloperKey(path.get("tenant"), request); + if (path.matches("/application/v4/tenant/{tenant}/secret-store/{name}")) return deleteSecretStore(path.get("tenant"), path.get("name"), request); if (path.matches("/application/v4/tenant/{tenant}/application/{application}")) return deleteApplication(path.get("tenant"), path.get("application"), request); if (path.matches("/application/v4/tenant/{tenant}/application/{application}/deployment")) return removeAllProdDeployments(path.get("tenant"), path.get("application")); if (path.matches("/application/v4/tenant/{tenant}/application/{application}/deploying")) return cancelDeploy(path.get("tenant"), path.get("application"), "default", "all"); @@ -702,6 +703,30 @@ public class ApplicationApiHandler extends LoggingRequestHandler { return new MessageResponse("Configured secret store: " + tenantSecretStore); } + private HttpResponse deleteSecretStore(String tenantName, String name, HttpRequest request) { + var tenant = (CloudTenant) controller.tenants().require(TenantName.from(tenantName)); + + var optionalSecretStore = tenant.tenantSecretStores().stream() + .filter(secretStore -> secretStore.getName().equals(name)) + .findFirst(); + + if (optionalSecretStore.isEmpty()) + return ErrorResponse.notFoundError("Could not delete secret store '" + name + "': Secret store not found"); + + var tenantSecretStore = optionalSecretStore.get(); + controller.serviceRegistry().tenantSecretService().deleteSecretStore(tenant.name(), tenantSecretStore); + controller.tenants().lockOrThrow(tenant.name(), LockedTenant.Cloud.class, lockedTenant -> { + lockedTenant = lockedTenant.withoutSecretStore(tenantSecretStore); + controller.tenants().store(lockedTenant); + }); + var slime = new Slime(); + var cursor = slime.setObject(); + cursor.setString("name", tenantSecretStore.getName()); + cursor.setString("awsId", tenantSecretStore.getAwsId()); + cursor.setString("role", tenantSecretStore.getRole()); + return new SlimeJsonResponse(slime); + } + private HttpResponse patchApplication(String tenantName, String applicationName, HttpRequest request) { Inspector requestObject = toSlime(request.getData()).get(); StringJoiner messageBuilder = new StringJoiner("\n").setEmptyValue("No applicable changes."); diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ServiceRegistryMock.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ServiceRegistryMock.java index 136b37b02e1..6ffac36fd6a 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ServiceRegistryMock.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ServiceRegistryMock.java @@ -212,7 +212,7 @@ public class ServiceRegistryMock extends AbstractComponent implements ServiceReg } @Override - public TenantSecretService tenantSecretService() { + public NoopTenantSecretService tenantSecretService() { return tenantSecretService; } diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiCloudTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiCloudTest.java index 6d8a1b6c025..88307018385 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiCloudTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiCloudTest.java @@ -20,6 +20,7 @@ import com.yahoo.vespa.hosted.controller.restapi.ControllerContainerCloudTest; import com.yahoo.vespa.hosted.controller.security.Auth0Credentials; import com.yahoo.vespa.hosted.controller.security.CloudTenantSpec; import com.yahoo.vespa.hosted.controller.security.Credentials; +import com.yahoo.vespa.hosted.controller.tenant.CloudTenant; import org.junit.Before; import org.junit.Test; @@ -28,9 +29,7 @@ import java.util.Collections; import java.util.Optional; import java.util.Set; -import static com.yahoo.application.container.handler.Request.Method.GET; -import static com.yahoo.application.container.handler.Request.Method.POST; -import static com.yahoo.application.container.handler.Request.Method.PUT; +import static com.yahoo.application.container.handler.Request.Method.*; import static com.yahoo.vespa.hosted.controller.restapi.application.ApplicationApiTest.createApplicationSubmissionData; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; @@ -183,6 +182,27 @@ public class ApplicationApiCloudTest extends ControllerContainerCloudTest { "}", 200); } + @Test + public void delete_secret_store() { + var deleteRequest = + request("/application/v4/tenant/scoober/secret-store/secret-foo", DELETE) + .roles(Set.of(Role.administrator(tenantName))); + tester.assertResponse(deleteRequest, "{" + + "\"error-code\":\"NOT_FOUND\"," + + "\"message\":\"Could not delete secret store 'secret-foo': Secret store not found\"" + + "}", 404); + + tester.controller().tenants().lockOrThrow(tenantName, LockedTenant.Cloud.class, lockedTenant -> { + lockedTenant = lockedTenant.withSecretStore(new TenantSecretStore("secret-foo", "123", "some-role")); + tester.controller().tenants().store(lockedTenant); + }); + var tenant = (CloudTenant) tester.controller().tenants().require(tenantName); + assertEquals(1, tenant.tenantSecretStores().size()); + tester.assertResponse(deleteRequest, "{\"name\":\"secret-foo\",\"awsId\":\"123\",\"role\":\"some-role\"}", 200); + tenant = (CloudTenant) tester.controller().tenants().require(tenantName); + assertEquals(0, tenant.tenantSecretStores().size()); + } + private ApplicationPackageBuilder prodBuilder() { return new ApplicationPackageBuilder() .instances("default") |