RED-6888: Add delete tenant endpoint

removed extra topic exchange
removed not needed event
fixed code errors
tested on stack
This commit is contained in:
yhampe 2024-01-25 09:49:48 +01:00
parent 64cecc4a7d
commit 819730d970
6 changed files with 68 additions and 88 deletions

View File

@ -40,7 +40,7 @@ public interface TenantsResource {
@Operation(summary = "Deletes given tenant", description = "None")
@ApiResponses(value = {@ApiResponse(responseCode = "204", description = "OK"), @ApiResponse(responseCode = "405", description = "Operation is not allowed."), @ApiResponse(responseCode = "409", description = "Conflict while deleting user.")})
@DeleteMapping(value = "/tenants/{tenantId}")
void deleteTenant(@PathVariable("tenantId") String tenantId, @RequestBody TenantRequest tenant);
void deleteTenant(@PathVariable("tenantId") String tenantId);
@GetMapping(value = "/tenants", produces = MediaType.APPLICATION_JSON_VALUE)

View File

@ -49,11 +49,10 @@ public class TenantsController implements TenantsResource, PublicResource {
}
}
@PreAuthorize("hasAuthority('"+ DELETE_TENANT+ "')")
public void deleteTenant(String tenantId, TenantRequest tenantRequest) {
public void deleteTenant(String tenantId) {
try {
tenantManagementService.deleteTenant(tenantId, tenantRequest);
tenantManagementService.deleteTenant(tenantId);
} catch (IllegalArgumentException e) {
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, e.getMessage(), e);
}

View File

@ -1,17 +0,0 @@
package com.knecon.fforesight.tenantusermanagement.events;
import com.knecon.fforesight.tenantcommons.model.SearchConnection;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@NoArgsConstructor
@Data
@AllArgsConstructor
public class TenantDeletedEvent {
private String tenantId;
private SearchConnection searchConnection;
}

View File

@ -20,13 +20,6 @@ public class MessagingConfiguration {
return new TopicExchange(tenantExchangeName);
}
@Bean
TopicExchange deleteTenantExchange(@Value("${fforesight.tenant-exchange.name}") String tenantExchangeName) {
return new TopicExchange(tenantExchangeName);
}
@Bean
TopicExchange userExchange(@Value("${fforesight.user-exchange.name}") String userExchangeName) {

View File

@ -14,7 +14,6 @@ import java.util.UUID;
import java.util.stream.Collectors;
import javax.sql.DataSource;
import javax.ws.rs.BadRequestException;
import javax.ws.rs.NotFoundException;
import org.apache.commons.lang3.StringUtils;
@ -34,7 +33,11 @@ import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;
import org.springframework.web.server.ResponseStatusException;
import com.azure.storage.blob.BlobClient;
import com.azure.storage.blob.BlobContainerClient;
import com.azure.storage.blob.BlobServiceClient;
import com.azure.storage.blob.BlobServiceClientBuilder;
import com.azure.storage.blob.models.BlobItem;
import com.fasterxml.jackson.databind.JsonNode;
import com.knecon.fforesight.tenantcommons.EncryptionDecryptionService;
import com.knecon.fforesight.tenantcommons.TenantContext;
@ -51,7 +54,6 @@ import com.knecon.fforesight.tenantusermanagement.entity.S3StorageConnectionEnti
import com.knecon.fforesight.tenantusermanagement.entity.SearchConnectionEntity;
import com.knecon.fforesight.tenantusermanagement.entity.TenantEntity;
import com.knecon.fforesight.tenantusermanagement.events.TenantCreatedEvent;
import com.knecon.fforesight.tenantusermanagement.events.TenantDeletedEvent;
import com.knecon.fforesight.tenantusermanagement.events.TenantSyncEvent;
import com.knecon.fforesight.tenantusermanagement.model.TenantRequest;
import com.knecon.fforesight.tenantusermanagement.model.TenantUser;
@ -62,7 +64,12 @@ import com.knecon.fforesight.tenantusermanagement.utils.JDBCUtils;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.model.DeleteBucketRequest;
import software.amazon.awssdk.services.s3.model.DeleteObjectRequest;
import software.amazon.awssdk.services.s3.model.ListObjectsRequest;
import software.amazon.awssdk.services.s3.model.ListObjectsResponse;
import software.amazon.awssdk.services.s3.model.S3Object;
@Slf4j
@Service
@ -89,10 +96,6 @@ public class TenantManagementService implements TenantProvider {
@Value("${fforesight.tenant-exchange.name}")
private String tenantExchangeName;
@Value("${fforesight.tenant-delete.name}")
private String tenantDeleteName;
@SneakyThrows
public TenantResponse createTenant(TenantRequest tenantRequest) {
@ -190,61 +193,63 @@ public class TenantManagementService implements TenantProvider {
}
@SneakyThrows
public void deleteTenant(String tenantId, TenantRequest tenantRequest) {
public void deleteTenant(String tenantId) {
log.info("Requested to delete tenant for: {}", tenantRequest.getTenantId());
TenantResponse tenant = this.getTenant(tenantId);
log.info("Requested to delete tenant for: {}", tenant.getTenantId());
if (tenantRequest.getS3StorageConnection() != null && tenantRequest.getAzureStorageConnection() != null) {
if (tenant.getS3StorageConnection() != null && tenant.getAzureStorageConnection() != null) {
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Not possible to set both azure and s3 connection, please only specify one");
}
var tenant = tenantRepository.findByTenantId(tenantId);
log.info("Deleting tenant: {}", tenant.getTenantId());
log.info("Deleting search index for tenant: {}", tenant.getTenantId());
TenantContext.setTenantId(tenant.getTenantId());
rabbitTemplate.convertAndSend(tenantExchangeName, "tenant.deleted", tenant);
TenantContext.clear();
log.info("Dispatched delete index message for tenant: {}", tenant.getTenantId());
deleteSchema(tenant);
if(tenant.getAzureStorageConnection() != null ) {
log.info("Deleting azure blob for tenant: {}",tenantId);
String connectionString = tenant.getAzureStorageConnection().getConnectionString();
String containerName = tenant.getAzureStorageConnection().getContainerName();
if (tenant.isPresent()) {
BlobServiceClient blobServiceClient = new BlobServiceClientBuilder().connectionString(connectionString).buildClient();
BlobContainerClient containerClient = blobServiceClient.getBlobContainerClient(containerName);
log.info("Deleting tenant: {}", tenantRequest.getTenantId());
var tenantEntity = tenant.get();
log.info("Deleting search index for tenant: {}", tenantRequest.getTenantId());
TenantContext.setTenantId(tenantEntity.getTenantId());
rabbitTemplate.convertAndSend(tenantDeleteName, "tenant.deleted", new TenantDeletedEvent(tenantEntity.getTenantId(),SearchConnection.builder()
.hosts(tenantEntity.getSearchConnection().getHosts())
.port(tenantEntity.getSearchConnection().getPort())
.scheme(tenantEntity.getSearchConnection().getScheme())
.username(tenantEntity.getSearchConnection().getUsername())
.numberOfShards(tenantEntity.getSearchConnection().getNumberOfShards())
.numberOfReplicas(tenantEntity.getSearchConnection().getNumberOfReplicas())
.password(tenantEntity.getSearchConnection().getPassword())
.indexPrefix(tenantEntity.getSearchConnection().getIndexPrefix())
.build()));
TenantContext.clear();
log.info("Dispatched delete index message for tenant: {}", tenantRequest.getTenantId());
//todo: delete cache
deleteSchema(tenantRequest);
com.iqser.red.storage.commons.model.AzureStorageConnection azureStorageConnection = new com.iqser.red.storage.commons.model.AzureStorageConnection(tenantRequest.getAzureStorageConnection().getConnectionString(), tenantRequest.getAzureStorageConnection().getContainerName());
if (azureStorageConnection != null) {
log.info("Deleting azure blob for tenant: {}",tenantId);
BlobServiceClient blobServiceClient = storageConfiguration.getAzureBlobStorageService().initBlobServiceClient(azureStorageConnection);
blobServiceClient.deleteBlobContainer(tenantRequest.getAzureStorageConnection().getContainerName());
// Delete all blobs within the container
for (BlobItem blobItem : containerClient.listBlobs()) {
BlobClient blobClient = containerClient.getBlobClient(blobItem.getName());
blobClient.delete();
}
var s3StorageConnectionTemplate = tenantRequest.getS3StorageConnection();
com.iqser.red.storage.commons.model.S3StorageConnection s3StorageConnection = new com.iqser.red.storage.commons.model.S3StorageConnection(s3StorageConnectionTemplate.getKey(), s3StorageConnectionTemplate.getSecret(), s3StorageConnectionTemplate.getSignerType(), s3StorageConnectionTemplate.getBucketName(), s3StorageConnectionTemplate.getRegion(),s3StorageConnectionTemplate.getEndpoint());
if (s3StorageConnection != null) {
log.info("Deleting s3 bucket for tenant: {}",tenantId);
DeleteBucketRequest deleteBucketRequest = DeleteBucketRequest.builder()
.bucket(s3StorageConnection.getBucketName())
.expectedBucketOwner(tenantId)
.build();
storageConfiguration.getS3StorageService().initAmazonS3(s3StorageConnection).deleteBucket(deleteBucketRequest);
}
deleteRealm(tenantId);
tenantRepository.delete(tenantEntity);
} else {
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Tenant does not exist");
containerClient.delete();
}
if(tenant.getS3StorageConnection() != null) {
var s3StorageConnectionTemplate = tenant.getS3StorageConnection();
com.iqser.red.storage.commons.model.S3StorageConnection s3StorageConnection = new com.iqser.red.storage.commons.model.S3StorageConnection(s3StorageConnectionTemplate.getKey(), encryptionService.decrypt(s3StorageConnectionTemplate.getSecret()), s3StorageConnectionTemplate.getSignerType(), s3StorageConnectionTemplate.getBucketName(), s3StorageConnectionTemplate.getRegion(),s3StorageConnectionTemplate.getEndpoint());
log.info("Deleting s3 bucket for tenant: {}",tenantId);
S3Client client = storageConfiguration.getS3StorageService().initAmazonS3(s3StorageConnection);
String bucketName = s3StorageConnection.getBucketName();
ListObjectsRequest listObjects = ListObjectsRequest
.builder()
.bucket(bucketName)
.build();
ListObjectsResponse objectList = client.listObjects(listObjects);
for (S3Object object : objectList.contents()) {
// Delete each object
client.deleteObject(DeleteObjectRequest.builder().bucket(bucketName).key(object.key()).build());
}
DeleteBucketRequest deleteBucketRequest = DeleteBucketRequest.builder()
.bucket(bucketName)
.expectedBucketOwner(tenantId)
.build();
client.deleteBucket(deleteBucketRequest);
}
deleteRealm(tenantId);
tenantRepository.deleteById(tenant.getTenantId());
}
@ -321,16 +326,18 @@ public class TenantManagementService implements TenantProvider {
}
}
private void deleteSchema(TenantRequest tenantRequest) {
log.info("Deleting schema for tenant: {}", tenantRequest.getTenantId());
var jdbcUrl = JDBCUtils.buildJdbcUrl(tenantRequest.getDatabaseConnection());
private void deleteSchema(TenantResponse tenant) {
log.info("Deleting schema for tenant: {}", tenant.getTenantId());
var jdbcUrl = JDBCUtils.buildJdbcUrl(tenant.getDatabaseConnection());
try (Connection connection = DriverManager.getConnection(jdbcUrl,
tenantRequest.getDatabaseConnection().getUsername(),
tenantRequest.getDatabaseConnection().getPassword())) {
tenant.getDatabaseConnection().getUsername(),
this.encryptionService.decrypt(tenant.getDatabaseConnection().getPassword())))
{
DataSource tenantDataSource = new SingleConnectionDataSource(connection, false);
JdbcTemplate jdbcTemplate = new JdbcTemplate(tenantDataSource);
String deleteStatement = "DELETE SCHEMA IF EXISTS \"" + tenantRequest.getDatabaseConnection().getSchema() + "\"";
jdbcTemplate.execute(deleteStatement);
String deleteStatement = "DROP SCHEMA IF EXISTS \"" + tenant.getDatabaseConnection().getSchema() + "\" CASCADE;";
jdbcTemplate.execute(deleteStatement);
} catch (Exception e) {
log.warn("Could not delete schema:", e);
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Tenant deletion failed: " + e.getMessage(), e);

View File

@ -110,8 +110,6 @@ fforesight:
app-prefix: 'fforesight'
tenant-exchange:
name: 'tenants-exchange'
tenant-delete:
name: 'tenant-delete-queue'
user-exchange:
name: 'users-exchange'
springdoc: