added entity usage
This commit is contained in:
parent
8edc55d48e
commit
8481b71b7e
@ -0,0 +1,45 @@
|
||||
/**
|
||||
* Copyright © 2016-2023 The Thingsboard Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.controller;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.thingsboard.server.common.data.UsageInfo;
|
||||
import org.thingsboard.server.common.data.exception.ThingsboardException;
|
||||
import org.thingsboard.server.dao.usage.UsageInfoService;
|
||||
import org.thingsboard.server.queue.util.TbCoreComponent;
|
||||
|
||||
@RestController
|
||||
@TbCoreComponent
|
||||
@RequestMapping("/api")
|
||||
@Slf4j
|
||||
public class UsageInfoController extends BaseController {
|
||||
|
||||
@Autowired
|
||||
private UsageInfoService usageInfoService;
|
||||
|
||||
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
|
||||
@RequestMapping(value = "/tenant/usageInfo", method = RequestMethod.GET)
|
||||
@ResponseBody
|
||||
public UsageInfo getTenantUsageInfo() throws ThingsboardException {
|
||||
return checkNotNull(usageInfoService.getUsageInfo(getCurrentUser().getTenantId()));
|
||||
}
|
||||
}
|
||||
@ -26,11 +26,13 @@ import org.thingsboard.common.util.JacksonUtil;
|
||||
import org.thingsboard.server.common.data.AdminSettings;
|
||||
import org.thingsboard.server.common.data.ApiUsageState;
|
||||
import org.thingsboard.server.common.data.Customer;
|
||||
import org.thingsboard.server.common.data.Dashboard;
|
||||
import org.thingsboard.server.common.data.Device;
|
||||
import org.thingsboard.server.common.data.EntityType;
|
||||
import org.thingsboard.server.common.data.FeaturesInfo;
|
||||
import org.thingsboard.server.common.data.Tenant;
|
||||
import org.thingsboard.server.common.data.TenantProfile;
|
||||
import org.thingsboard.server.common.data.UsageInfo;
|
||||
import org.thingsboard.server.common.data.User;
|
||||
import org.thingsboard.server.common.data.asset.Asset;
|
||||
import org.thingsboard.server.common.data.id.TenantId;
|
||||
@ -49,7 +51,9 @@ import org.thingsboard.server.common.data.query.EntityData;
|
||||
import org.thingsboard.server.common.data.query.EntityTypeFilter;
|
||||
import org.thingsboard.server.common.data.query.TsValue;
|
||||
import org.thingsboard.server.common.data.security.Authority;
|
||||
import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration;
|
||||
import org.thingsboard.server.common.stats.TbApiUsageStateClient;
|
||||
import org.thingsboard.server.dao.tenant.TbTenantProfileCache;
|
||||
import org.thingsboard.server.service.ws.telemetry.cmd.v2.EntityCountCmd;
|
||||
import org.thingsboard.server.service.ws.telemetry.cmd.v2.EntityCountUpdate;
|
||||
import org.thingsboard.server.service.ws.telemetry.cmd.v2.EntityDataUpdate;
|
||||
@ -69,6 +73,9 @@ public abstract class BaseHomePageApiTest extends AbstractControllerTest {
|
||||
@Autowired
|
||||
private TbApiUsageStateClient apiUsageStateClient;
|
||||
|
||||
@Autowired
|
||||
private TbTenantProfileCache tenantProfileCache;
|
||||
|
||||
//For system administrator
|
||||
@Test
|
||||
public void testTenantsCountWsCmd() throws Exception {
|
||||
@ -329,6 +336,99 @@ public abstract class BaseHomePageApiTest extends AbstractControllerTest {
|
||||
Assert.assertTrue(featuresInfo.isOauthEnabled());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUsageInfo() throws Exception {
|
||||
loginTenantAdmin();
|
||||
|
||||
TenantProfile tenantProfile = tenantProfileCache.get(tenantId);
|
||||
|
||||
Assert.assertNotNull(tenantProfile);
|
||||
|
||||
DefaultTenantProfileConfiguration configuration = (DefaultTenantProfileConfiguration) tenantProfile.getProfileData().getConfiguration();
|
||||
|
||||
UsageInfo usageInfo = doGet("/api/tenant/usageInfo", UsageInfo.class);
|
||||
Assert.assertNotNull(usageInfo);
|
||||
Assert.assertEquals(0, usageInfo.getDevices());
|
||||
Assert.assertEquals(configuration.getMaxDevices(), usageInfo.getMaxDevices());
|
||||
|
||||
Assert.assertEquals(0, usageInfo.getAssets());
|
||||
Assert.assertEquals(configuration.getMaxAssets(), usageInfo.getMaxAssets());
|
||||
|
||||
Assert.assertEquals(1, usageInfo.getCustomers());
|
||||
Assert.assertEquals(configuration.getMaxCustomers(), usageInfo.getMaxCustomers());
|
||||
|
||||
Assert.assertEquals(2, usageInfo.getUsers());
|
||||
Assert.assertEquals(configuration.getMaxUsers(), usageInfo.getMaxUsers());
|
||||
|
||||
Assert.assertEquals(0, usageInfo.getDashboards());
|
||||
Assert.assertEquals(configuration.getMaxDashboards(), usageInfo.getMaxDashboards());
|
||||
|
||||
Assert.assertEquals(0, usageInfo.getTransportMessages());
|
||||
Assert.assertEquals(configuration.getMaxTransportMessages(), usageInfo.getMaxTransportMessages());
|
||||
|
||||
Assert.assertEquals(0, usageInfo.getJsExecutions());
|
||||
Assert.assertEquals(configuration.getMaxJSExecutions(), usageInfo.getMaxJsExecutions());
|
||||
|
||||
Assert.assertEquals(0, usageInfo.getEmails());
|
||||
Assert.assertEquals(configuration.getMaxEmails(), usageInfo.getMaxEmails());
|
||||
|
||||
Assert.assertEquals(0, usageInfo.getSms());
|
||||
Assert.assertEquals(configuration.getMaxSms(), usageInfo.getMaxSms());
|
||||
|
||||
Assert.assertEquals(0, usageInfo.getAlarms());
|
||||
Assert.assertEquals(configuration.getMaxCreatedAlarms(), usageInfo.getMaxAlarms());
|
||||
|
||||
List<Device> devices = new ArrayList<>();
|
||||
for (int i = 0; i < 97; i++) {
|
||||
Device device = new Device();
|
||||
device.setName("device" + i);
|
||||
devices.add(doPost("/api/device", device, Device.class));
|
||||
}
|
||||
|
||||
usageInfo = doGet("/api/tenant/usageInfo", UsageInfo.class);
|
||||
Assert.assertEquals(devices.size(), usageInfo.getDevices());
|
||||
|
||||
List<Asset> assets = new ArrayList<>();
|
||||
for (int i = 0; i < 97; i++) {
|
||||
Asset asset = new Asset();
|
||||
asset.setName("asset" + i);
|
||||
assets.add(doPost("/api/asset", asset, Asset.class));
|
||||
}
|
||||
|
||||
usageInfo = doGet("/api/tenant/usageInfo", UsageInfo.class);
|
||||
Assert.assertEquals(assets.size(), usageInfo.getAssets());
|
||||
|
||||
List<Customer> customers = new ArrayList<>();
|
||||
for (int i = 0; i < 97; i++) {
|
||||
Customer customer = new Customer();
|
||||
customer.setTitle("customer" + i);
|
||||
customers.add(doPost("/api/customer", customer, Customer.class));
|
||||
}
|
||||
|
||||
usageInfo = doGet("/api/tenant/usageInfo", UsageInfo.class);
|
||||
Assert.assertEquals(customers.size() + 1, usageInfo.getCustomers());
|
||||
|
||||
List<User> users = new ArrayList<>();
|
||||
for (int i = 0; i < 97; i++) {
|
||||
User user = new User();
|
||||
user.setAuthority(Authority.TENANT_ADMIN);
|
||||
user.setEmail(i + "user@thingsboard.org");
|
||||
users.add(doPost("/api/user", user, User.class));
|
||||
}
|
||||
|
||||
usageInfo = doGet("/api/tenant/usageInfo", UsageInfo.class);
|
||||
Assert.assertEquals(users.size() + 2, usageInfo.getUsers());
|
||||
|
||||
List<Dashboard> dashboards = new ArrayList<>();
|
||||
for (int i = 0; i < 97; i++) {
|
||||
Dashboard dashboard = new Dashboard();
|
||||
dashboard.setTitle("dashboard" + i);
|
||||
dashboards.add(doPost("/api/dashboard", dashboard, Dashboard.class));
|
||||
}
|
||||
|
||||
usageInfo = doGet("/api/tenant/usageInfo", UsageInfo.class);
|
||||
Assert.assertEquals(dashboards.size(), usageInfo.getDashboards());
|
||||
}
|
||||
|
||||
private OAuth2Info createDefaultOAuth2Info() {
|
||||
return new OAuth2Info(true, Lists.newArrayList(
|
||||
|
||||
@ -0,0 +1,25 @@
|
||||
/**
|
||||
* Copyright © 2016-2023 The Thingsboard Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.dao.usage;
|
||||
|
||||
import org.thingsboard.server.common.data.UsageInfo;
|
||||
import org.thingsboard.server.common.data.id.TenantId;
|
||||
|
||||
public interface UsageInfoService {
|
||||
|
||||
UsageInfo getUsageInfo(TenantId tenantId);
|
||||
|
||||
}
|
||||
@ -0,0 +1,43 @@
|
||||
/**
|
||||
* Copyright © 2016-2023 The Thingsboard Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.common.data;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class UsageInfo {
|
||||
private long devices;
|
||||
private long maxDevices;
|
||||
private long assets;
|
||||
private long maxAssets;
|
||||
private long customers;
|
||||
private long maxCustomers;
|
||||
private long users;
|
||||
private long maxUsers;
|
||||
private long dashboards;
|
||||
private long maxDashboards;
|
||||
|
||||
private long transportMessages;
|
||||
private long maxTransportMessages;
|
||||
private long jsExecutions;
|
||||
private long maxJsExecutions;
|
||||
private long emails;
|
||||
private long maxEmails;
|
||||
private long sms;
|
||||
private long maxSms;
|
||||
private long alarms;
|
||||
private long maxAlarms;
|
||||
}
|
||||
@ -0,0 +1,109 @@
|
||||
/**
|
||||
* Copyright © 2016-2023 The Thingsboard Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.dao.usage;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.thingsboard.server.common.data.ApiUsageRecordKey;
|
||||
import org.thingsboard.server.common.data.ApiUsageState;
|
||||
import org.thingsboard.server.common.data.UsageInfo;
|
||||
import org.thingsboard.server.common.data.id.TenantId;
|
||||
import org.thingsboard.server.common.data.kv.TsKvEntry;
|
||||
import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration;
|
||||
import org.thingsboard.server.dao.asset.AssetDao;
|
||||
import org.thingsboard.server.dao.customer.CustomerDao;
|
||||
import org.thingsboard.server.dao.dashboard.DashboardDao;
|
||||
import org.thingsboard.server.dao.device.DeviceDao;
|
||||
import org.thingsboard.server.dao.tenant.TbTenantProfileCache;
|
||||
import org.thingsboard.server.dao.timeseries.TimeseriesService;
|
||||
import org.thingsboard.server.dao.usagerecord.ApiUsageStateService;
|
||||
import org.thingsboard.server.dao.user.UserDao;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class BasicUsageInfoService implements UsageInfoService {
|
||||
|
||||
private final DeviceDao deviceDao;
|
||||
private final AssetDao assetDao;
|
||||
private final CustomerDao customerDao;
|
||||
private final UserDao userDao;
|
||||
private final DashboardDao dashboardDao;
|
||||
private final ApiUsageStateService apiUsageStateService;
|
||||
private final TimeseriesService tsService;
|
||||
@Lazy
|
||||
private final TbTenantProfileCache tenantProfileCache;
|
||||
|
||||
@Override
|
||||
public UsageInfo getUsageInfo(TenantId tenantId) {
|
||||
DefaultTenantProfileConfiguration profileConfiguration =
|
||||
(DefaultTenantProfileConfiguration) tenantProfileCache.get(tenantId).getProfileData().getConfiguration();
|
||||
UsageInfo usageInfo = new UsageInfo();
|
||||
usageInfo.setDevices(deviceDao.countByTenantId(tenantId));
|
||||
usageInfo.setMaxDevices(profileConfiguration.getMaxDevices());
|
||||
usageInfo.setAssets(assetDao.countByTenantId(tenantId));
|
||||
usageInfo.setMaxAssets(profileConfiguration.getMaxAssets());
|
||||
usageInfo.setCustomers(customerDao.countByTenantId(tenantId));
|
||||
usageInfo.setMaxCustomers(profileConfiguration.getMaxCustomers());
|
||||
usageInfo.setUsers(userDao.countByTenantId(tenantId));
|
||||
usageInfo.setMaxUsers(profileConfiguration.getMaxUsers());
|
||||
usageInfo.setDashboards(dashboardDao.countByTenantId(tenantId));
|
||||
usageInfo.setMaxDashboards(profileConfiguration.getMaxDashboards());
|
||||
|
||||
usageInfo.setMaxAlarms(profileConfiguration.getMaxCreatedAlarms());
|
||||
usageInfo.setMaxTransportMessages(profileConfiguration.getMaxTransportMessages());
|
||||
usageInfo.setMaxJsExecutions(profileConfiguration.getMaxJSExecutions());
|
||||
usageInfo.setMaxEmails(profileConfiguration.getMaxEmails());
|
||||
usageInfo.setMaxSms(profileConfiguration.getMaxSms());
|
||||
ApiUsageState apiUsageState = apiUsageStateService.findTenantApiUsageState(tenantId);
|
||||
if (apiUsageState != null) {
|
||||
Collection<String> keys = Arrays.asList(
|
||||
ApiUsageRecordKey.TRANSPORT_MSG_COUNT.getApiCountKey(),
|
||||
ApiUsageRecordKey.JS_EXEC_COUNT.getApiCountKey(),
|
||||
ApiUsageRecordKey.EMAIL_EXEC_COUNT.getApiCountKey(),
|
||||
ApiUsageRecordKey.SMS_EXEC_COUNT.getApiCountKey(),
|
||||
ApiUsageRecordKey.CREATED_ALARMS_COUNT.getApiCountKey());
|
||||
try {
|
||||
List<TsKvEntry> entries = tsService.findLatest(tenantId, apiUsageState.getId(), keys).get();
|
||||
usageInfo.setTransportMessages(getLongValueFromTsEntries(entries, ApiUsageRecordKey.TRANSPORT_MSG_COUNT.getApiCountKey()));
|
||||
usageInfo.setJsExecutions(getLongValueFromTsEntries(entries, ApiUsageRecordKey.JS_EXEC_COUNT.getApiCountKey()));
|
||||
usageInfo.setEmails(getLongValueFromTsEntries(entries, ApiUsageRecordKey.EMAIL_EXEC_COUNT.getApiCountKey()));
|
||||
usageInfo.setSms(getLongValueFromTsEntries(entries, ApiUsageRecordKey.SMS_EXEC_COUNT.getApiCountKey()));
|
||||
usageInfo.setAlarms(getLongValueFromTsEntries(entries, ApiUsageRecordKey.CREATED_ALARMS_COUNT.getApiCountKey()));
|
||||
} catch (ExecutionException | InterruptedException e) {
|
||||
throw new RuntimeException("Failed to fetch api usage values from timeseries!");
|
||||
}
|
||||
}
|
||||
return usageInfo;
|
||||
}
|
||||
|
||||
private long getLongValueFromTsEntries(List<TsKvEntry> entries, String key) {
|
||||
Optional<TsKvEntry> entryOpt = entries.stream().filter(e -> e.getKey().equals(key)).findFirst();
|
||||
if (entryOpt.isPresent() && entryOpt.get().getLongValue().isPresent()) {
|
||||
return entryOpt.get().getLongValue().get();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -63,6 +63,7 @@ import org.thingsboard.server.common.data.Tenant;
|
||||
import org.thingsboard.server.common.data.TenantInfo;
|
||||
import org.thingsboard.server.common.data.TenantProfile;
|
||||
import org.thingsboard.server.common.data.UpdateMessage;
|
||||
import org.thingsboard.server.common.data.UsageInfo;
|
||||
import org.thingsboard.server.common.data.User;
|
||||
import org.thingsboard.server.common.data.alarm.Alarm;
|
||||
import org.thingsboard.server.common.data.alarm.AlarmComment;
|
||||
@ -2467,6 +2468,14 @@ public class RestClient implements Closeable {
|
||||
}, params).getBody();
|
||||
}
|
||||
|
||||
public UsageInfo getUsageInfo() {
|
||||
return restTemplate.exchange(
|
||||
baseURL + "/api/tenant/usageInfo",
|
||||
HttpMethod.GET,
|
||||
HttpEntity.EMPTY,
|
||||
UsageInfo.class).getBody();
|
||||
}
|
||||
|
||||
public Optional<TenantProfile> getTenantProfileById(TenantProfileId tenantProfileId) {
|
||||
try {
|
||||
ResponseEntity<TenantProfile> tenantProfile = restTemplate.getForEntity(baseURL + "/api/tenantProfile/{tenantProfileId}", TenantProfile.class, tenantProfileId);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user