fix: use license/usage endpoint for agent/env/app counts
Some checks failed
CI / docker (push) Has been cancelled
CI / build (push) Has been cancelled

Server moved GET /agents to /environments/{envSlug}/agents and removed
GET /admin/apps. Replace three broken individual calls with a single
GET /admin/license/usage call that returns all counts.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
hsiegeln
2026-04-28 12:58:35 +02:00
parent c43d7f639f
commit bc32d7e994
4 changed files with 38 additions and 49 deletions

View File

@@ -125,51 +125,37 @@ public class ServerApiClient {
}
}
/** Fetch agent count from a tenant's server. */
public int getAgentCount(String serverEndpoint) {
try {
var resp = RestClient.create().get()
.uri(serverEndpoint + "/api/v1/agents")
.header("Authorization", "Bearer " + getAccessToken())
.header("X-Cameleer-Protocol-Version", "1")
.retrieve()
.body(java.util.List.class);
return resp != null ? resp.size() : 0;
} catch (Exception e) {
log.warn("Agent count fetch failed for {}: {}", serverEndpoint, e.getMessage());
return 0;
}
public record UsageCounts(int agents, int environments, int apps) {
public static final UsageCounts ZERO = new UsageCounts(0, 0, 0);
}
/** Fetch environment count from a tenant's server. */
public int getEnvironmentCount(String serverEndpoint) {
/** Fetch usage counts from a tenant's server via the license usage endpoint. */
@SuppressWarnings("unchecked")
public UsageCounts getUsageCounts(String serverEndpoint) {
try {
var resp = RestClient.create().get()
.uri(serverEndpoint + "/api/v1/admin/environments")
.uri(serverEndpoint + "/api/v1/admin/license/usage")
.header("Authorization", "Bearer " + getAccessToken())
.header("X-Cameleer-Protocol-Version", "1")
.retrieve()
.body(java.util.List.class);
return resp != null ? resp.size() : 0;
.body(Map.class);
if (resp == null) return UsageCounts.ZERO;
var limits = (List<Map<String, Object>>) resp.get("limits");
if (limits == null) return UsageCounts.ZERO;
int agents = 0, environments = 0, apps = 0;
for (var row : limits) {
String key = (String) row.get("key");
int current = ((Number) row.get("current")).intValue();
switch (key) {
case "max_agents" -> agents = current;
case "max_environments" -> environments = current;
case "max_apps" -> apps = current;
}
}
return new UsageCounts(agents, environments, apps);
} catch (Exception e) {
log.warn("Environment count fetch failed for {}: {}", serverEndpoint, e.getMessage());
return 0;
}
}
/** Fetch app count from a tenant's server. */
public int getAppCount(String serverEndpoint) {
try {
var resp = RestClient.create().get()
.uri(serverEndpoint + "/api/v1/admin/apps")
.header("Authorization", "Bearer " + getAccessToken())
.header("X-Cameleer-Protocol-Version", "1")
.retrieve()
.body(java.util.List.class);
return resp != null ? resp.size() : 0;
} catch (Exception e) {
log.warn("App count fetch failed for {}: {}", serverEndpoint, e.getMessage());
return 0;
log.warn("Usage counts fetch failed for {}: {}", serverEndpoint, e.getMessage());
return UsageCounts.ZERO;
}
}

View File

@@ -113,8 +113,9 @@ public class TenantPortalService {
serverHealthy = health.healthy();
serverStatus = health.status();
if (serverHealthy) {
agentCount = serverApiClient.getAgentCount(endpoint);
environmentCount = serverApiClient.getEnvironmentCount(endpoint);
var counts = serverApiClient.getUsageCounts(endpoint);
agentCount = counts.agents();
environmentCount = counts.environments();
}
}
@@ -160,9 +161,10 @@ public class TenantPortalService {
Map<String, Integer> usage = new HashMap<>();
String endpoint = tenant.getServerEndpoint();
if (endpoint != null && !endpoint.isBlank()) {
usage.put("agents", serverApiClient.getAgentCount(endpoint));
usage.put("environments", serverApiClient.getEnvironmentCount(endpoint));
usage.put("apps", serverApiClient.getAppCount(endpoint));
var counts = serverApiClient.getUsageCounts(endpoint);
usage.put("agents", counts.agents());
usage.put("environments", counts.environments());
usage.put("apps", counts.apps());
}
// User count from Logto org membership
String orgId = tenant.getLogtoOrgId();

View File

@@ -80,8 +80,9 @@ public class VendorTenantController {
boolean isActive = "ACTIVE".equals(tenant.getStatus().name());
if (isActive && endpoint != null && !endpoint.isBlank() && "RUNNING".equals(status.state().name())) {
var serverApi = vendorTenantService.getServerApiClient();
agentCount = serverApi.getAgentCount(endpoint);
environmentCount = serverApi.getEnvironmentCount(endpoint);
var counts = serverApi.getUsageCounts(endpoint);
agentCount = counts.agents();
environmentCount = counts.environments();
}
var license = vendorTenantService.getLicenseForTenant(tenant.getId());
if (license.isPresent() && license.get().getLimits() != null) {
@@ -130,9 +131,10 @@ public class VendorTenantController {
String endpoint = tenant.getServerEndpoint();
if (health.healthy() && endpoint != null && !endpoint.isBlank()) {
var serverApi = vendorTenantService.getServerApiClient();
usage.put("agents", serverApi.getAgentCount(endpoint));
usage.put("environments", serverApi.getEnvironmentCount(endpoint));
usage.put("apps", serverApi.getAppCount(endpoint));
var counts = serverApi.getUsageCounts(endpoint);
usage.put("agents", counts.agents());
usage.put("environments", counts.environments());
usage.put("apps", counts.apps());
}
return ResponseEntity.ok(new VendorTenantDetail(

View File

@@ -108,8 +108,7 @@ class TenantPortalServiceTest {
when(tenantService.getById(tenantId)).thenReturn(Optional.of(tenant));
when(serverApiClient.getHealth("http://server:8080")).thenReturn(new ServerHealthResponse(true, "UP"));
when(serverApiClient.getAgentCount("http://server:8080")).thenReturn(3);
when(serverApiClient.getEnvironmentCount("http://server:8080")).thenReturn(1);
when(serverApiClient.getUsageCounts("http://server:8080")).thenReturn(new ServerApiClient.UsageCounts(3, 1, 2));
when(licenseService.getActiveLicense(tenantId)).thenReturn(Optional.of(license));
var result = tenantPortalService.getDashboard();