fix: re-provision containers when restart finds them missing
When Docker containers have been removed (e.g. manual cleanup or image update), restart now falls back to full re-provisioning instead of failing with 404. Applies to both vendor and tenant portal restart. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -9,6 +9,10 @@ import net.siegeln.cameleer.saas.provisioning.ProvisioningProperties;
|
||||
import net.siegeln.cameleer.saas.provisioning.TenantProvisioner;
|
||||
import net.siegeln.cameleer.saas.tenant.TenantEntity;
|
||||
import net.siegeln.cameleer.saas.tenant.TenantService;
|
||||
import net.siegeln.cameleer.saas.vendor.VendorTenantService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.Instant;
|
||||
@@ -20,25 +24,30 @@ import java.util.UUID;
|
||||
@Service
|
||||
public class TenantPortalService {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(TenantPortalService.class);
|
||||
|
||||
private final TenantService tenantService;
|
||||
private final LicenseService licenseService;
|
||||
private final ServerApiClient serverApiClient;
|
||||
private final LogtoManagementClient logtoClient;
|
||||
private final TenantProvisioner tenantProvisioner;
|
||||
private final ProvisioningProperties provisioningProps;
|
||||
private final VendorTenantService vendorTenantService;
|
||||
|
||||
public TenantPortalService(TenantService tenantService,
|
||||
LicenseService licenseService,
|
||||
ServerApiClient serverApiClient,
|
||||
LogtoManagementClient logtoClient,
|
||||
TenantProvisioner tenantProvisioner,
|
||||
ProvisioningProperties provisioningProps) {
|
||||
ProvisioningProperties provisioningProps,
|
||||
@Lazy VendorTenantService vendorTenantService) {
|
||||
this.tenantService = tenantService;
|
||||
this.licenseService = licenseService;
|
||||
this.serverApiClient = serverApiClient;
|
||||
this.logtoClient = logtoClient;
|
||||
this.tenantProvisioner = tenantProvisioner;
|
||||
this.provisioningProps = provisioningProps;
|
||||
this.vendorTenantService = vendorTenantService;
|
||||
}
|
||||
|
||||
// --- Inner records ---
|
||||
@@ -180,9 +189,22 @@ public class TenantPortalService {
|
||||
|
||||
public void restartServer() {
|
||||
TenantEntity tenant = resolveTenant();
|
||||
if (tenantProvisioner.isAvailable()) {
|
||||
tenantProvisioner.stop(tenant.getSlug());
|
||||
if (!tenantProvisioner.isAvailable()) return;
|
||||
|
||||
tenantProvisioner.stop(tenant.getSlug());
|
||||
try {
|
||||
tenantProvisioner.start(tenant.getSlug());
|
||||
} catch (RuntimeException e) {
|
||||
if (e.getMessage() != null && e.getMessage().contains("re-provision required")) {
|
||||
log.info("Containers missing for '{}' — re-provisioning", tenant.getSlug());
|
||||
tenantProvisioner.remove(tenant.getSlug());
|
||||
var license = licenseService.getActiveLicense(tenant.getId()).orElse(null);
|
||||
String token = license != null ? license.getToken() : "";
|
||||
vendorTenantService.provisionAsync(
|
||||
tenant.getId(), tenant.getSlug(), tenant.getTier().name(), token, null);
|
||||
return;
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,6 +73,9 @@ public class DockerTenantProvisioner implements TenantProvisioner {
|
||||
try {
|
||||
docker.startContainerCmd(serverContainerName(slug)).exec();
|
||||
docker.startContainerCmd(uiContainerName(slug)).exec();
|
||||
} catch (NotFoundException e) {
|
||||
log.warn("Containers for '{}' not found — cannot start (re-provision needed)", slug);
|
||||
throw new RuntimeException("Containers not found for '" + slug + "' — re-provision required", e);
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to start containers for '{}'", slug, e);
|
||||
throw new RuntimeException("Start failed: " + e.getMessage(), e);
|
||||
|
||||
@@ -220,9 +220,21 @@ public class VendorTenantService {
|
||||
public void restartServer(UUID tenantId) {
|
||||
TenantEntity tenant = tenantService.getById(tenantId)
|
||||
.orElseThrow(() -> new IllegalArgumentException("Tenant not found"));
|
||||
if (tenantProvisioner.isAvailable()) {
|
||||
tenantProvisioner.stop(tenant.getSlug());
|
||||
if (!tenantProvisioner.isAvailable()) return;
|
||||
|
||||
tenantProvisioner.stop(tenant.getSlug());
|
||||
try {
|
||||
tenantProvisioner.start(tenant.getSlug());
|
||||
} catch (RuntimeException e) {
|
||||
if (e.getMessage() != null && e.getMessage().contains("re-provision required")) {
|
||||
log.info("Containers missing for '{}' — re-provisioning", tenant.getSlug());
|
||||
tenantProvisioner.remove(tenant.getSlug());
|
||||
var license = licenseService.getActiveLicense(tenantId).orElse(null);
|
||||
String token = license != null ? license.getToken() : "";
|
||||
provisionAsync(tenantId, tenant.getSlug(), tenant.getTier().name(), token, null);
|
||||
return;
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ class TenantPortalServiceTest {
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
TenantContext.setTenantId(tenantId);
|
||||
tenantPortalService = new TenantPortalService(tenantService, licenseService, serverApiClient, logtoClient, tenantProvisioner, provisioningProps);
|
||||
tenantPortalService = new TenantPortalService(tenantService, licenseService, serverApiClient, logtoClient, tenantProvisioner, provisioningProps, null);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
|
||||
Reference in New Issue
Block a user