feat: create per-tenant PG database during provisioning, drop on delete
Inject TenantDatabaseService; call createTenantDatabase() at the start of provisionAsync() (stores generated password on TenantEntity), and dropTenantDatabase() in delete() before GDPR data erasure. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -6,6 +6,7 @@ import net.siegeln.cameleer.saas.identity.LogtoConfig;
|
||||
import net.siegeln.cameleer.saas.identity.LogtoManagementClient;
|
||||
import net.siegeln.cameleer.saas.identity.ServerApiClient;
|
||||
import net.siegeln.cameleer.saas.provisioning.ProvisioningProperties;
|
||||
import net.siegeln.cameleer.saas.provisioning.TenantDatabaseService;
|
||||
import net.siegeln.cameleer.saas.provisioning.TenantDataCleanupService;
|
||||
import net.siegeln.cameleer.saas.identity.ServerApiClient.ServerHealthResponse;
|
||||
import net.siegeln.cameleer.saas.license.LicenseEntity;
|
||||
@@ -47,6 +48,7 @@ public class VendorTenantService {
|
||||
private final AuditService auditService;
|
||||
private final ProvisioningProperties provisioningProps;
|
||||
private final TenantDataCleanupService dataCleanupService;
|
||||
private final TenantDatabaseService tenantDatabaseService;
|
||||
|
||||
public VendorTenantService(TenantService tenantService,
|
||||
TenantRepository tenantRepository,
|
||||
@@ -57,7 +59,8 @@ public class VendorTenantService {
|
||||
LogtoConfig logtoConfig,
|
||||
AuditService auditService,
|
||||
ProvisioningProperties provisioningProps,
|
||||
TenantDataCleanupService dataCleanupService) {
|
||||
TenantDataCleanupService dataCleanupService,
|
||||
TenantDatabaseService tenantDatabaseService) {
|
||||
this.tenantService = tenantService;
|
||||
this.tenantRepository = tenantRepository;
|
||||
this.licenseService = licenseService;
|
||||
@@ -68,6 +71,7 @@ public class VendorTenantService {
|
||||
this.auditService = auditService;
|
||||
this.provisioningProps = provisioningProps;
|
||||
this.dataCleanupService = dataCleanupService;
|
||||
this.tenantDatabaseService = tenantDatabaseService;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@@ -119,7 +123,30 @@ public class VendorTenantService {
|
||||
@Async
|
||||
public void provisionAsync(UUID tenantId, String slug, String tier, String licenseToken, UUID actorId) {
|
||||
try {
|
||||
var provisionRequest = new TenantProvisionRequest(tenantId, slug, tier, licenseToken);
|
||||
// Create per-tenant PG user + schema
|
||||
String dbPassword = java.util.UUID.randomUUID().toString().replace("-", "")
|
||||
+ java.util.UUID.randomUUID().toString().replace("-", "").substring(0, 8);
|
||||
try {
|
||||
tenantDatabaseService.createTenantDatabase(slug, dbPassword);
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to create tenant database for {}: {}", slug, e.getMessage(), e);
|
||||
tenantRepository.findById(tenantId).ifPresent(t -> {
|
||||
t.setProvisionError("Database setup failed: " + e.getMessage());
|
||||
tenantRepository.save(t);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Store DB password on entity
|
||||
TenantEntity tenantForDb = tenantRepository.findById(tenantId).orElse(null);
|
||||
if (tenantForDb == null) {
|
||||
log.error("Tenant {} disappeared during provisioning", slug);
|
||||
return;
|
||||
}
|
||||
tenantForDb.setDbPassword(dbPassword);
|
||||
tenantRepository.save(tenantForDb);
|
||||
|
||||
var provisionRequest = new TenantProvisionRequest(tenantId, slug, tier, licenseToken, dbPassword);
|
||||
ProvisionResult result = tenantProvisioner.provision(provisionRequest);
|
||||
|
||||
TenantEntity tenant = tenantRepository.findById(tenantId).orElse(null);
|
||||
@@ -302,7 +329,15 @@ public class VendorTenantService {
|
||||
}
|
||||
}
|
||||
|
||||
// Drop per-tenant PG user + database
|
||||
try {
|
||||
tenantDatabaseService.dropTenantDatabase(tenant.getSlug());
|
||||
} catch (Exception e) {
|
||||
log.warn("Failed to drop tenant database for {}: {}", tenant.getSlug(), e.getMessage());
|
||||
}
|
||||
|
||||
// Erase tenant data from server databases (GDPR)
|
||||
// TODO: split into cleanupClickHouse() in next task
|
||||
dataCleanupService.cleanup(tenant.getSlug());
|
||||
|
||||
// Soft-delete
|
||||
|
||||
Reference in New Issue
Block a user