125 changed files with 2058 additions and 954 deletions
@ -0,0 +1,213 @@ |
|||
/** |
|||
* 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.service.system; |
|||
|
|||
import com.fasterxml.jackson.databind.JsonNode; |
|||
import com.google.common.util.concurrent.FutureCallback; |
|||
import com.google.protobuf.ProtocolStringList; |
|||
import lombok.RequiredArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.stereotype.Service; |
|||
import org.thingsboard.common.util.JacksonUtil; |
|||
import org.thingsboard.common.util.ThingsBoardThreadFactory; |
|||
import org.thingsboard.server.common.data.AdminSettings; |
|||
import org.thingsboard.server.common.data.ApiUsageState; |
|||
import org.thingsboard.server.common.data.FeaturesInfo; |
|||
import org.thingsboard.server.common.data.SystemInfo; |
|||
import org.thingsboard.server.common.data.SystemInfoData; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.kv.BasicTsKvEntry; |
|||
import org.thingsboard.server.common.data.kv.DoubleDataEntry; |
|||
import org.thingsboard.server.common.data.kv.JsonDataEntry; |
|||
import org.thingsboard.server.common.data.kv.LongDataEntry; |
|||
import org.thingsboard.server.common.data.kv.TsKvEntry; |
|||
import org.thingsboard.server.common.msg.queue.ServiceType; |
|||
import org.thingsboard.server.common.stats.TbApiUsageStateClient; |
|||
import org.thingsboard.server.dao.oauth2.OAuth2Service; |
|||
import org.thingsboard.server.dao.service.DataValidator; |
|||
import org.thingsboard.server.dao.settings.AdminSettingsService; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ServiceInfo; |
|||
import org.thingsboard.server.queue.discovery.DiscoveryService; |
|||
import org.thingsboard.server.queue.discovery.PartitionService; |
|||
import org.thingsboard.server.queue.discovery.TbApplicationEventListener; |
|||
import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; |
|||
import org.thingsboard.server.queue.discovery.event.PartitionChangeEvent; |
|||
import org.thingsboard.server.queue.util.TbCoreComponent; |
|||
import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService; |
|||
|
|||
import javax.annotation.Nullable; |
|||
import javax.annotation.PreDestroy; |
|||
import java.util.ArrayList; |
|||
import java.util.Collections; |
|||
import java.util.List; |
|||
import java.util.concurrent.Executors; |
|||
import java.util.concurrent.ScheduledExecutorService; |
|||
import java.util.concurrent.TimeUnit; |
|||
|
|||
import static org.thingsboard.common.util.SystemUtil.getCpuUsage; |
|||
import static org.thingsboard.common.util.SystemUtil.getFreeDiscSpace; |
|||
import static org.thingsboard.common.util.SystemUtil.getFreeMemory; |
|||
import static org.thingsboard.common.util.SystemUtil.getMemoryUsage; |
|||
import static org.thingsboard.common.util.SystemUtil.getTotalCpuUsage; |
|||
import static org.thingsboard.common.util.SystemUtil.getTotalDiscSpace; |
|||
import static org.thingsboard.common.util.SystemUtil.getTotalMemory; |
|||
|
|||
@TbCoreComponent |
|||
@Service |
|||
@RequiredArgsConstructor |
|||
@Slf4j |
|||
public class DefaultSystemInfoService extends TbApplicationEventListener<PartitionChangeEvent> implements SystemInfoService { |
|||
|
|||
public static final FutureCallback<Integer> CALLBACK = new FutureCallback<>() { |
|||
@Override |
|||
public void onSuccess(@Nullable Integer result) { |
|||
} |
|||
|
|||
@Override |
|||
public void onFailure(Throwable t) { |
|||
log.warn("Failed to persist system info", t); |
|||
} |
|||
}; |
|||
|
|||
private final TbServiceInfoProvider serviceInfoProvider; |
|||
private final PartitionService partitionService; |
|||
private final DiscoveryService discoveryService; |
|||
private final TelemetrySubscriptionService telemetryService; |
|||
private final TbApiUsageStateClient apiUsageStateClient; |
|||
private final AdminSettingsService adminSettingsService; |
|||
private final OAuth2Service oAuth2Service; |
|||
private volatile ScheduledExecutorService scheduler; |
|||
|
|||
@Override |
|||
protected void onTbApplicationEvent(PartitionChangeEvent partitionChangeEvent) { |
|||
if (ServiceType.TB_CORE.equals(partitionChangeEvent.getServiceType())) { |
|||
boolean myPartition = partitionService.resolve(ServiceType.TB_CORE, TenantId.SYS_TENANT_ID, TenantId.SYS_TENANT_ID).isMyPartition(); |
|||
synchronized (this) { |
|||
if (myPartition) { |
|||
if (scheduler == null) { |
|||
scheduler = Executors.newSingleThreadScheduledExecutor(ThingsBoardThreadFactory.forName("tb-system-info-scheduler")); |
|||
scheduler.scheduleAtFixedRate(this::saveCurrentSystemInfo, 0, 1, TimeUnit.MINUTES); |
|||
} |
|||
} else { |
|||
destroy(); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public SystemInfo getSystemInfo() { |
|||
SystemInfo systemInfo = new SystemInfo(); |
|||
|
|||
if (discoveryService.isMonolith()) { |
|||
systemInfo.setMonolith(true); |
|||
systemInfo.setSystemData(Collections.singletonList(createSystemInfoData(serviceInfoProvider.generateNewServiceInfoWithCurrentSystemInfo()))); |
|||
} else { |
|||
systemInfo.setSystemData(getSystemData(serviceInfoProvider.getServiceInfo())); |
|||
} |
|||
|
|||
return systemInfo; |
|||
} |
|||
|
|||
protected void saveCurrentSystemInfo() { |
|||
if (discoveryService.isMonolith()) { |
|||
saveCurrentMonolithSystemInfo(); |
|||
} else { |
|||
saveCurrentClusterSystemInfo(); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public FeaturesInfo getFeaturesInfo() { |
|||
FeaturesInfo featuresInfo = new FeaturesInfo(); |
|||
featuresInfo.setEmailEnabled(isEmailEnabled()); |
|||
featuresInfo.setSmsEnabled(adminSettingsService.findAdminSettingsByKey(TenantId.SYS_TENANT_ID, "sms") != null); |
|||
featuresInfo.setOauthEnabled(oAuth2Service.findOAuth2Info().isEnabled()); |
|||
featuresInfo.setTwoFaEnabled(adminSettingsService.findAdminSettingsByKey(TenantId.SYS_TENANT_ID, "twoFaSettings") != null); |
|||
featuresInfo.setNotificationEnabled(adminSettingsService.findAdminSettingsByKey(TenantId.SYS_TENANT_ID, "notifications") != null); |
|||
return featuresInfo; |
|||
} |
|||
|
|||
private boolean isEmailEnabled() { |
|||
AdminSettings mailSettings = adminSettingsService.findAdminSettingsByKey(TenantId.SYS_TENANT_ID, "mail"); |
|||
if (mailSettings != null) { |
|||
JsonNode mailFrom = mailSettings.getJsonValue().get("mailFrom"); |
|||
if (mailFrom != null) { |
|||
return DataValidator.doValidateEmail(mailFrom.asText()); |
|||
} |
|||
} |
|||
return false; |
|||
} |
|||
|
|||
private void saveCurrentClusterSystemInfo() { |
|||
long ts = System.currentTimeMillis(); |
|||
List<SystemInfoData> clusterSystemData = getSystemData(serviceInfoProvider.getServiceInfo()); |
|||
BasicTsKvEntry clusterDataKv = new BasicTsKvEntry(ts, new JsonDataEntry("clusterSystemData", JacksonUtil.toString(clusterSystemData))); |
|||
doSave(Collections.singletonList(clusterDataKv)); |
|||
} |
|||
|
|||
private void saveCurrentMonolithSystemInfo() { |
|||
long ts = System.currentTimeMillis(); |
|||
List<TsKvEntry> tsList = new ArrayList<>(); |
|||
getMemoryUsage().ifPresent(v -> tsList.add(new BasicTsKvEntry(ts, new LongDataEntry("memoryUsage", v)))); |
|||
getTotalMemory().ifPresent(v -> tsList.add(new BasicTsKvEntry(ts, new LongDataEntry("totalMemory", v)))); |
|||
getFreeMemory().ifPresent(v -> tsList.add(new BasicTsKvEntry(ts, new LongDataEntry("freeMemory", v)))); |
|||
getCpuUsage().ifPresent(v -> tsList.add(new BasicTsKvEntry(ts, new DoubleDataEntry("cpuUsage", v)))); |
|||
getTotalCpuUsage().ifPresent(v -> tsList.add(new BasicTsKvEntry(ts, new DoubleDataEntry("totalCpuUsage", v)))); |
|||
getFreeDiscSpace().ifPresent(v -> tsList.add(new BasicTsKvEntry(ts, new LongDataEntry("freeDiscSpace", v)))); |
|||
getTotalDiscSpace().ifPresent(v -> tsList.add(new BasicTsKvEntry(ts, new LongDataEntry("totalDiscSpace", v)))); |
|||
|
|||
doSave(tsList); |
|||
} |
|||
|
|||
private void doSave(List<TsKvEntry> telemetry) { |
|||
ApiUsageState apiUsageState = apiUsageStateClient.getApiUsageState(TenantId.SYS_TENANT_ID); |
|||
telemetryService.saveAndNotifyInternal(TenantId.SYS_TENANT_ID, apiUsageState.getId(), telemetry, CALLBACK); |
|||
} |
|||
|
|||
private List<SystemInfoData> getSystemData(ServiceInfo serviceInfo) { |
|||
List<SystemInfoData> clusterSystemData = new ArrayList<>(); |
|||
clusterSystemData.add(createSystemInfoData(serviceInfo)); |
|||
this.discoveryService.getOtherServers() |
|||
.stream() |
|||
.map(this::createSystemInfoData) |
|||
.forEach(clusterSystemData::add); |
|||
return clusterSystemData; |
|||
} |
|||
|
|||
private SystemInfoData createSystemInfoData(ServiceInfo serviceInfo) { |
|||
ProtocolStringList serviceTypes = serviceInfo.getServiceTypesList(); |
|||
SystemInfoData infoData = new SystemInfoData(); |
|||
infoData.setServiceId(serviceInfo.getServiceId()); |
|||
infoData.setServiceType(serviceTypes.size() > 1 ? "MONOLITH" : serviceTypes.get(0)); |
|||
infoData.setMemoryUsage(serviceInfo.getSystemInfo().getMemoryUsage()); |
|||
infoData.setTotalMemory(serviceInfo.getSystemInfo().getTotalMemory()); |
|||
infoData.setFreeMemory(serviceInfo.getSystemInfo().getFreeMemory()); |
|||
infoData.setCpuUsage(serviceInfo.getSystemInfo().getCpuUsage()); |
|||
infoData.setTotalCpuUsage(serviceInfo.getSystemInfo().getTotalCpuUsage()); |
|||
infoData.setFreeDiscSpace(serviceInfo.getSystemInfo().getFreeDiscSpace()); |
|||
infoData.setTotalDiscSpace(serviceInfo.getSystemInfo().getTotalDiscSpace()); |
|||
return infoData; |
|||
} |
|||
|
|||
@PreDestroy |
|||
private void destroy() { |
|||
if (scheduler != null) { |
|||
scheduler.shutdownNow(); |
|||
scheduler = null; |
|||
} |
|||
} |
|||
} |
|||
@ -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.service.system; |
|||
|
|||
import org.thingsboard.server.common.data.FeaturesInfo; |
|||
import org.thingsboard.server.common.data.SystemInfo; |
|||
|
|||
public interface SystemInfoService { |
|||
SystemInfo getSystemInfo(); |
|||
|
|||
FeaturesInfo getFeaturesInfo(); |
|||
} |
|||
@ -0,0 +1,372 @@ |
|||
/** |
|||
* 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 com.fasterxml.jackson.databind.JsonNode; |
|||
import com.fasterxml.jackson.databind.node.ObjectNode; |
|||
import com.google.common.collect.Lists; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.junit.Assert; |
|||
import org.junit.Test; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
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.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.User; |
|||
import org.thingsboard.server.common.data.asset.Asset; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.oauth2.MapperType; |
|||
import org.thingsboard.server.common.data.oauth2.OAuth2CustomMapperConfig; |
|||
import org.thingsboard.server.common.data.oauth2.OAuth2DomainInfo; |
|||
import org.thingsboard.server.common.data.oauth2.OAuth2Info; |
|||
import org.thingsboard.server.common.data.oauth2.OAuth2MapperConfig; |
|||
import org.thingsboard.server.common.data.oauth2.OAuth2ParamsInfo; |
|||
import org.thingsboard.server.common.data.oauth2.OAuth2RegistrationInfo; |
|||
import org.thingsboard.server.common.data.oauth2.SchemeType; |
|||
import org.thingsboard.server.common.data.page.PageData; |
|||
import org.thingsboard.server.common.data.query.ApiUsageStateFilter; |
|||
import org.thingsboard.server.common.data.query.EntityCountQuery; |
|||
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.stats.TbApiUsageStateClient; |
|||
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; |
|||
|
|||
import java.util.ArrayList; |
|||
import java.util.Arrays; |
|||
import java.util.Collections; |
|||
import java.util.List; |
|||
import java.util.UUID; |
|||
import java.util.concurrent.TimeUnit; |
|||
|
|||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; |
|||
|
|||
@Slf4j |
|||
public abstract class BaseHomePageApiTest extends AbstractControllerTest { |
|||
|
|||
@Autowired |
|||
private TbApiUsageStateClient apiUsageStateClient; |
|||
|
|||
//For system administrator
|
|||
@Test |
|||
public void testTenantsCountWsCmd() throws Exception { |
|||
loginSysAdmin(); |
|||
|
|||
List<Tenant> tenants = new ArrayList<>(); |
|||
for (int i = 0; i < 100; i++) { |
|||
Tenant tenant = new Tenant(); |
|||
tenant.setTitle("tenant" + i); |
|||
tenants.add(doPost("/api/tenant", tenant, Tenant.class)); |
|||
} |
|||
|
|||
EntityTypeFilter ef = new EntityTypeFilter(); |
|||
ef.setEntityType(EntityType.TENANT); |
|||
EntityCountCmd cmd = new EntityCountCmd(1, new EntityCountQuery(ef, Collections.emptyList())); |
|||
getWsClient().send(cmd); |
|||
EntityCountUpdate update = getWsClient().parseCountReply(getWsClient().waitForReply()); |
|||
Assert.assertEquals(1, update.getCmdId()); |
|||
Assert.assertEquals(101, update.getCount()); |
|||
|
|||
for (Tenant tenant : tenants) { |
|||
doDelete("/api/tenant/" + tenant.getId().toString()); |
|||
} |
|||
} |
|||
|
|||
@Test |
|||
public void testTenantProfilesCountWsCmd() throws Exception { |
|||
loginSysAdmin(); |
|||
|
|||
List<TenantProfile> tenantProfiles = new ArrayList<>(); |
|||
for (int i = 0; i < 100; i++) { |
|||
TenantProfile tenantProfile = new TenantProfile(); |
|||
tenantProfile.setName("tenantProfile" + i); |
|||
tenantProfiles.add(doPost("/api/tenantProfile", tenantProfile, TenantProfile.class)); |
|||
} |
|||
|
|||
EntityTypeFilter ef = new EntityTypeFilter(); |
|||
ef.setEntityType(EntityType.TENANT_PROFILE); |
|||
EntityCountCmd cmd = new EntityCountCmd(1, new EntityCountQuery(ef, Collections.emptyList())); |
|||
getWsClient().send(cmd); |
|||
EntityCountUpdate update = getWsClient().parseCountReply(getWsClient().waitForReply()); |
|||
Assert.assertEquals(1, update.getCmdId()); |
|||
Assert.assertEquals(101, update.getCount()); |
|||
|
|||
for (TenantProfile tenantProfile : tenantProfiles) { |
|||
doDelete("/api/tenantProfile/" + tenantProfile.getId().toString()); |
|||
} |
|||
} |
|||
|
|||
@Test |
|||
public void testUsersCountWsCmd() throws Exception { |
|||
loginSysAdmin(); |
|||
|
|||
List<User> users = new ArrayList<>(); |
|||
for (int i = 0; i < 100; i++) { |
|||
User user = new User(); |
|||
user.setEmail(i + "user@thingsboard.org"); |
|||
user.setTenantId(tenantId); |
|||
user.setAuthority(Authority.TENANT_ADMIN); |
|||
users.add(doPost("/api/user", user, User.class)); |
|||
} |
|||
|
|||
EntityTypeFilter ef = new EntityTypeFilter(); |
|||
ef.setEntityType(EntityType.USER); |
|||
EntityCountCmd cmd = new EntityCountCmd(1, new EntityCountQuery(ef, Collections.emptyList())); |
|||
getWsClient().send(cmd); |
|||
EntityCountUpdate update = getWsClient().parseCountReply(getWsClient().waitForReply()); |
|||
Assert.assertEquals(1, update.getCmdId()); |
|||
Assert.assertEquals(103, update.getCount()); |
|||
|
|||
for (User user : users) { |
|||
doDelete("/api/user/" + user.getId().toString()); |
|||
} |
|||
} |
|||
|
|||
@Test |
|||
public void testCustomersCountWsCmd() throws Exception { |
|||
loginTenantAdmin(); |
|||
|
|||
List<Customer> customers = new ArrayList<>(); |
|||
for (int i = 0; i < 100; i++) { |
|||
Customer customer = new Customer(); |
|||
customer.setTitle("customer" + i); |
|||
customers.add(doPost("/api/customer", customer, Customer.class)); |
|||
} |
|||
|
|||
loginSysAdmin(); |
|||
EntityTypeFilter ef = new EntityTypeFilter(); |
|||
ef.setEntityType(EntityType.CUSTOMER); |
|||
EntityCountCmd cmd = new EntityCountCmd(1, new EntityCountQuery(ef, Collections.emptyList())); |
|||
getWsClient().send(cmd); |
|||
EntityCountUpdate update = getWsClient().parseCountReply(getWsClient().waitForReply()); |
|||
Assert.assertEquals(1, update.getCmdId()); |
|||
Assert.assertEquals(101, update.getCount()); |
|||
|
|||
loginTenantAdmin(); |
|||
for (Customer customer : customers) { |
|||
doDelete("/api/customer/" + customer.getId().toString()); |
|||
} |
|||
} |
|||
|
|||
@Test |
|||
public void testDevicesCountWsCmd() throws Exception { |
|||
loginTenantAdmin(); |
|||
|
|||
List<Device> devices = new ArrayList<>(); |
|||
for (int i = 0; i < 100; i++) { |
|||
Device device = new Device(); |
|||
device.setName("device" + i); |
|||
devices.add(doPost("/api/device", device, Device.class)); |
|||
} |
|||
|
|||
loginSysAdmin(); |
|||
EntityTypeFilter ef = new EntityTypeFilter(); |
|||
ef.setEntityType(EntityType.DEVICE); |
|||
EntityCountCmd cmd = new EntityCountCmd(1, new EntityCountQuery(ef, Collections.emptyList())); |
|||
getWsClient().send(cmd); |
|||
EntityCountUpdate update = getWsClient().parseCountReply(getWsClient().waitForReply()); |
|||
Assert.assertEquals(1, update.getCmdId()); |
|||
Assert.assertEquals(100, update.getCount()); |
|||
|
|||
loginTenantAdmin(); |
|||
for (Device device : devices) { |
|||
doDelete("/api/device/" + device.getId().toString()); |
|||
} |
|||
} |
|||
|
|||
@Test |
|||
public void testAssetsCountWsCmd() throws Exception { |
|||
loginTenantAdmin(); |
|||
|
|||
List<Asset> assets = new ArrayList<>(); |
|||
for (int i = 0; i < 100; i++) { |
|||
Asset asset = new Asset(); |
|||
asset.setName("asset" + i); |
|||
assets.add(doPost("/api/asset", asset, Asset.class)); |
|||
} |
|||
|
|||
loginSysAdmin(); |
|||
EntityTypeFilter ef = new EntityTypeFilter(); |
|||
ef.setEntityType(EntityType.ASSET); |
|||
EntityCountCmd cmd = new EntityCountCmd(1, new EntityCountQuery(ef, Collections.emptyList())); |
|||
getWsClient().send(cmd); |
|||
EntityCountUpdate update = getWsClient().parseCountReply(getWsClient().waitForReply()); |
|||
Assert.assertEquals(1, update.getCmdId()); |
|||
Assert.assertEquals(100, update.getCount()); |
|||
|
|||
loginTenantAdmin(); |
|||
for (Asset asset : assets) { |
|||
doDelete("/api/asset/" + asset.getId().toString()); |
|||
} |
|||
} |
|||
|
|||
@Test |
|||
public void testSystemInfoTimeSeriesWsCmd() throws Exception { |
|||
ApiUsageState apiUsageState = apiUsageStateClient.getApiUsageState(TenantId.SYS_TENANT_ID); |
|||
Assert.assertNotNull(apiUsageState); |
|||
|
|||
loginSysAdmin(); |
|||
long now = System.currentTimeMillis(); |
|||
|
|||
EntityDataUpdate update = getWsClient().sendEntityDataQuery(new ApiUsageStateFilter()); |
|||
|
|||
Assert.assertEquals(1, update.getCmdId()); |
|||
PageData<EntityData> pageData = update.getData(); |
|||
Assert.assertNotNull(pageData); |
|||
Assert.assertEquals(1, pageData.getData().size()); |
|||
Assert.assertEquals(apiUsageState.getId(), pageData.getData().get(0).getEntityId()); |
|||
|
|||
update = getWsClient().subscribeTsUpdate( |
|||
List.of("memoryUsage", "totalMemory", "freeMemory", "cpuUsage", "totalCpuUsage", "freeDiscSpace", "totalDiscSpace"), |
|||
now, TimeUnit.HOURS.toMillis(1)); |
|||
Assert.assertEquals(1, update.getCmdId()); |
|||
List<EntityData> listData = update.getUpdate(); |
|||
Assert.assertNotNull(listData); |
|||
Assert.assertEquals(1, listData.size()); |
|||
Assert.assertEquals(apiUsageState.getId(), listData.get(0).getEntityId()); |
|||
Assert.assertEquals(7, listData.get(0).getTimeseries().size()); |
|||
|
|||
for (TsValue[] tsv : listData.get(0).getTimeseries().values()) { |
|||
Assert.assertTrue(tsv.length > 0); |
|||
} |
|||
} |
|||
|
|||
@Test |
|||
public void testGetFeaturesInfo() throws Exception { |
|||
loginSysAdmin(); |
|||
|
|||
FeaturesInfo featuresInfo = doGet("/api/admin/featuresInfo", FeaturesInfo.class); |
|||
Assert.assertNotNull(featuresInfo); |
|||
Assert.assertFalse(featuresInfo.isEmailEnabled()); |
|||
Assert.assertFalse(featuresInfo.isSmsEnabled()); |
|||
Assert.assertFalse(featuresInfo.isTwoFaEnabled()); |
|||
Assert.assertFalse(featuresInfo.isNotificationEnabled()); |
|||
Assert.assertFalse(featuresInfo.isOauthEnabled()); |
|||
|
|||
AdminSettings mailSettings = doGet("/api/admin/settings/mail", AdminSettings.class); |
|||
|
|||
JsonNode jsonValue = mailSettings.getJsonValue(); |
|||
((ObjectNode) jsonValue).put("mailFrom", "test@thingsboard.org"); |
|||
mailSettings.setJsonValue(jsonValue); |
|||
|
|||
doPost("/api/admin/settings", mailSettings).andExpect(status().isOk()); |
|||
|
|||
featuresInfo = doGet("/api/admin/featuresInfo", FeaturesInfo.class); |
|||
Assert.assertTrue(featuresInfo.isEmailEnabled()); |
|||
Assert.assertFalse(featuresInfo.isSmsEnabled()); |
|||
Assert.assertFalse(featuresInfo.isTwoFaEnabled()); |
|||
Assert.assertFalse(featuresInfo.isNotificationEnabled()); |
|||
Assert.assertFalse(featuresInfo.isOauthEnabled()); |
|||
|
|||
AdminSettings smsSettings = new AdminSettings(); |
|||
smsSettings.setKey("sms"); |
|||
smsSettings.setJsonValue(JacksonUtil.newObjectNode()); |
|||
doPost("/api/admin/settings", smsSettings).andExpect(status().isOk()); |
|||
|
|||
featuresInfo = doGet("/api/admin/featuresInfo", FeaturesInfo.class); |
|||
Assert.assertTrue(featuresInfo.isEmailEnabled()); |
|||
Assert.assertTrue(featuresInfo.isSmsEnabled()); |
|||
Assert.assertFalse(featuresInfo.isTwoFaEnabled()); |
|||
Assert.assertFalse(featuresInfo.isNotificationEnabled()); |
|||
Assert.assertFalse(featuresInfo.isOauthEnabled()); |
|||
|
|||
AdminSettings twoFaSettingsSettings = new AdminSettings(); |
|||
twoFaSettingsSettings.setKey("twoFaSettings"); |
|||
twoFaSettingsSettings.setJsonValue(JacksonUtil.newObjectNode()); |
|||
doPost("/api/admin/settings", twoFaSettingsSettings).andExpect(status().isOk()); |
|||
|
|||
featuresInfo = doGet("/api/admin/featuresInfo", FeaturesInfo.class); |
|||
Assert.assertTrue(featuresInfo.isEmailEnabled()); |
|||
Assert.assertTrue(featuresInfo.isSmsEnabled()); |
|||
Assert.assertTrue(featuresInfo.isTwoFaEnabled()); |
|||
Assert.assertFalse(featuresInfo.isNotificationEnabled()); |
|||
Assert.assertFalse(featuresInfo.isOauthEnabled()); |
|||
|
|||
AdminSettings notificationsSettings = new AdminSettings(); |
|||
notificationsSettings.setKey("notifications"); |
|||
notificationsSettings.setJsonValue(JacksonUtil.newObjectNode()); |
|||
doPost("/api/admin/settings", notificationsSettings).andExpect(status().isOk()); |
|||
|
|||
featuresInfo = doGet("/api/admin/featuresInfo", FeaturesInfo.class); |
|||
Assert.assertTrue(featuresInfo.isEmailEnabled()); |
|||
Assert.assertTrue(featuresInfo.isSmsEnabled()); |
|||
Assert.assertTrue(featuresInfo.isTwoFaEnabled()); |
|||
Assert.assertTrue(featuresInfo.isNotificationEnabled()); |
|||
Assert.assertFalse(featuresInfo.isOauthEnabled()); |
|||
|
|||
OAuth2Info oAuth2Info = createDefaultOAuth2Info(); |
|||
|
|||
doPost("/api/oauth2/config", oAuth2Info).andExpect(status().isOk()); |
|||
|
|||
featuresInfo = doGet("/api/admin/featuresInfo", FeaturesInfo.class); |
|||
Assert.assertNotNull(featuresInfo); |
|||
Assert.assertTrue(featuresInfo.isEmailEnabled()); |
|||
Assert.assertTrue(featuresInfo.isSmsEnabled()); |
|||
Assert.assertTrue(featuresInfo.isTwoFaEnabled()); |
|||
Assert.assertTrue(featuresInfo.isNotificationEnabled()); |
|||
Assert.assertTrue(featuresInfo.isOauthEnabled()); |
|||
} |
|||
|
|||
|
|||
private OAuth2Info createDefaultOAuth2Info() { |
|||
return new OAuth2Info(true, Lists.newArrayList( |
|||
OAuth2ParamsInfo.builder() |
|||
.domainInfos(Lists.newArrayList( |
|||
OAuth2DomainInfo.builder().name("domain").scheme(SchemeType.MIXED).build() |
|||
)) |
|||
.mobileInfos(Collections.emptyList()) |
|||
.clientRegistrations(Lists.newArrayList( |
|||
validRegistrationInfo() |
|||
)) |
|||
.build() |
|||
)); |
|||
} |
|||
|
|||
private OAuth2RegistrationInfo validRegistrationInfo() { |
|||
return OAuth2RegistrationInfo.builder() |
|||
.clientId(UUID.randomUUID().toString()) |
|||
.clientSecret(UUID.randomUUID().toString()) |
|||
.authorizationUri(UUID.randomUUID().toString()) |
|||
.accessTokenUri(UUID.randomUUID().toString()) |
|||
.scope(Arrays.asList(UUID.randomUUID().toString(), UUID.randomUUID().toString())) |
|||
.platforms(Collections.emptyList()) |
|||
.userInfoUri(UUID.randomUUID().toString()) |
|||
.userNameAttributeName(UUID.randomUUID().toString()) |
|||
.jwkSetUri(UUID.randomUUID().toString()) |
|||
.clientAuthenticationMethod(UUID.randomUUID().toString()) |
|||
.loginButtonLabel(UUID.randomUUID().toString()) |
|||
.mapperConfig( |
|||
OAuth2MapperConfig.builder() |
|||
.type(MapperType.CUSTOM) |
|||
.custom( |
|||
OAuth2CustomMapperConfig.builder() |
|||
.url(UUID.randomUUID().toString()) |
|||
.build() |
|||
) |
|||
.build() |
|||
) |
|||
.build(); |
|||
} |
|||
} |
|||
@ -0,0 +1,23 @@ |
|||
/** |
|||
* 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.sql; |
|||
|
|||
import org.thingsboard.server.controller.BaseHomePageApiTest; |
|||
import org.thingsboard.server.dao.service.DaoSqlTest; |
|||
|
|||
@DaoSqlTest |
|||
public class HomePageApiSqlTest extends BaseHomePageApiTest { |
|||
} |
|||
@ -0,0 +1,27 @@ |
|||
/** |
|||
* 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 FeaturesInfo { |
|||
boolean isEmailEnabled; |
|||
boolean isSmsEnabled; |
|||
boolean isNotificationEnabled; |
|||
boolean isOauthEnabled; |
|||
boolean isTwoFaEnabled; |
|||
} |
|||
@ -0,0 +1,29 @@ |
|||
/** |
|||
* 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 io.swagger.annotations.ApiModelProperty; |
|||
import lombok.Data; |
|||
|
|||
import java.util.List; |
|||
|
|||
@Data |
|||
public class SystemInfo { |
|||
@ApiModelProperty(position = 1, value = "Is monolith.") |
|||
private boolean isMonolith; |
|||
@ApiModelProperty(position = 2, value = "System data.") |
|||
private List<SystemInfoData> systemData; |
|||
} |
|||
@ -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 io.swagger.annotations.ApiModelProperty; |
|||
import lombok.Data; |
|||
|
|||
import java.util.Map; |
|||
|
|||
@Data |
|||
public class SystemInfoData { |
|||
@ApiModelProperty(position = 1, value = "Service Id.") |
|||
private String serviceId; |
|||
@ApiModelProperty(position = 2, value = "Service type.") |
|||
private String serviceType; |
|||
@ApiModelProperty(position = 3, value = "CPU usage.") |
|||
private Double cpuUsage; |
|||
@ApiModelProperty(position = 4, value = "Total CPU usage.") |
|||
private Double totalCpuUsage; |
|||
@ApiModelProperty(position = 5, value = "Memory usage in bytes.") |
|||
private Long memoryUsage; |
|||
@ApiModelProperty(position = 6, value = "Total memory in bytes.") |
|||
private Long totalMemory; |
|||
@ApiModelProperty(position = 6, value = "Free memory in bytes.") |
|||
private Long freeMemory; |
|||
@ApiModelProperty(position = 7, value = "Free disc space in bytes.") |
|||
private Long freeDiscSpace; |
|||
@ApiModelProperty(position = 7, value = "Total disc space in bytes.") |
|||
private Long totalDiscSpace; |
|||
} |
|||
@ -0,0 +1,108 @@ |
|||
/** |
|||
* 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.common.util; |
|||
|
|||
import lombok.extern.slf4j.Slf4j; |
|||
import oshi.SystemInfo; |
|||
import oshi.hardware.HardwareAbstractionLayer; |
|||
|
|||
import java.lang.management.ManagementFactory; |
|||
import java.lang.management.MemoryMXBean; |
|||
import java.nio.file.FileStore; |
|||
import java.nio.file.Files; |
|||
import java.nio.file.Paths; |
|||
import java.util.Optional; |
|||
|
|||
@Slf4j |
|||
public class SystemUtil { |
|||
|
|||
private static final HardwareAbstractionLayer HARDWARE; |
|||
|
|||
static { |
|||
SystemInfo si = new SystemInfo(); |
|||
HARDWARE = si.getHardware(); |
|||
} |
|||
|
|||
public static Optional<Long> getMemoryUsage() { |
|||
try { |
|||
MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean(); |
|||
return Optional.of(memoryMXBean.getHeapMemoryUsage().getUsed()); |
|||
} catch (Exception e) { |
|||
log.debug("Failed to get memory usage!!!", e); |
|||
} |
|||
return Optional.empty(); |
|||
} |
|||
|
|||
public static Optional<Long> getTotalMemory() { |
|||
try { |
|||
return Optional.of(HARDWARE.getMemory().getTotal()); |
|||
} catch (Exception e) { |
|||
log.debug("Failed to get total memory!!!", e); |
|||
} |
|||
return Optional.empty(); |
|||
} |
|||
|
|||
public static Optional<Long> getFreeMemory() { |
|||
try { |
|||
return Optional.of(HARDWARE.getMemory().getAvailable()); |
|||
} catch (Exception e) { |
|||
log.debug("Failed to get free memory!!!", e); |
|||
} |
|||
return Optional.empty(); |
|||
} |
|||
|
|||
public static Optional<Double> getCpuUsage() { |
|||
try { |
|||
return Optional.of(prepare(HARDWARE.getProcessor().getSystemLoadAverage())); |
|||
} catch (Exception e) { |
|||
log.debug("Failed to get cpu usage!!!", e); |
|||
} |
|||
return Optional.empty(); |
|||
} |
|||
|
|||
public static Optional<Double> getTotalCpuUsage() { |
|||
try { |
|||
return Optional.of(prepare(HARDWARE.getProcessor().getSystemCpuLoad() * 100)); |
|||
} catch (Exception e) { |
|||
log.debug("Failed to get total cpu usage!!!", e); |
|||
} |
|||
return Optional.empty(); |
|||
} |
|||
|
|||
public static Optional<Long> getFreeDiscSpace() { |
|||
try { |
|||
FileStore store = Files.getFileStore(Paths.get("/")); |
|||
return Optional.of(store.getUsableSpace()); |
|||
} catch (Exception e) { |
|||
log.debug("Failed to get free disc space!!!", e); |
|||
} |
|||
return Optional.empty(); |
|||
} |
|||
|
|||
public static Optional<Long> getTotalDiscSpace() { |
|||
try { |
|||
FileStore store = Files.getFileStore(Paths.get("/")); |
|||
return Optional.of(store.getTotalSpace()); |
|||
} catch (Exception e) { |
|||
log.debug("Failed to get total disc space!!!", e); |
|||
} |
|||
return Optional.empty(); |
|||
} |
|||
|
|||
private static Double prepare(Double d) { |
|||
return (int) (d * 100) / 100.0; |
|||
} |
|||
} |
|||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue