Browse Source

Resources shortage notification template & rule

pull/12616/head
Andrii Landiak 2 years ago
parent
commit
89e7b95d19
  1. 1
      application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java
  2. 50
      application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/ResourcesShortageLimitTriggerProcessor.java
  3. 22
      application/src/main/java/org/thingsboard/server/service/system/DefaultSystemInfoService.java
  4. 3
      common/data/src/main/java/org/thingsboard/server/common/data/notification/NotificationType.java
  5. 42
      common/data/src/main/java/org/thingsboard/server/common/data/notification/info/ResourcesShortageNotificationInfo.java
  6. 5
      common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/NewPlatformVersionTrigger.java
  7. 71
      common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/ResourcesShortageTrigger.java
  8. 10
      common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/TaskProcessingFailureTrigger.java
  9. 3
      common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/config/NotificationRuleTriggerConfig.java
  10. 3
      common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/config/NotificationRuleTriggerType.java
  11. 48
      common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/config/ResourcesShortageNotificationRuleTriggerConfig.java
  12. 4
      dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationSettingsService.java
  13. 16
      dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotifications.java
  14. 60
      ui-ngx/src/app/modules/home/pages/notification/rule/rule-notification-dialog.component.html
  15. 15
      ui-ngx/src/app/modules/home/pages/notification/rule/rule-notification-dialog.component.ts
  16. 3
      ui-ngx/src/app/modules/home/pages/notification/template/template-notification-dialog.component.ts
  17. 16
      ui-ngx/src/app/shared/models/notification.models.ts
  18. 42
      ui-ngx/src/assets/help/en_US/notification/resources_shortage.md
  19. 8
      ui-ngx/src/assets/locale/locale.constant-en_US.json

1
application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java

@ -116,6 +116,7 @@ public class ThingsboardInstallService {
entityDatabaseSchemaService.createDatabaseIndexes(); entityDatabaseSchemaService.createDatabaseIndexes();
// TODO: cleanup update code after each release // TODO: cleanup update code after each release
systemDataLoaderService.updateDefaultNotificationConfigs(false);
// Runs upgrade scripts that are not possible in plain SQL. // Runs upgrade scripts that are not possible in plain SQL.
dataUpdateService.updateData(); dataUpdateService.updateData();

50
application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/ResourcesShortageLimitTriggerProcessor.java

@ -0,0 +1,50 @@
/**
* Copyright © 2016-2024 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.notification.rule.trigger;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.notification.info.ResourcesShortageNotificationInfo;
import org.thingsboard.server.common.data.notification.info.RuleOriginatedNotificationInfo;
import org.thingsboard.server.common.data.notification.rule.trigger.ResourcesShortageTrigger;
import org.thingsboard.server.common.data.notification.rule.trigger.config.NotificationRuleTriggerType;
import org.thingsboard.server.common.data.notification.rule.trigger.config.ResourcesShortageNotificationRuleTriggerConfig;
@Service
@RequiredArgsConstructor
public class ResourcesShortageLimitTriggerProcessor implements NotificationRuleTriggerProcessor<ResourcesShortageTrigger, ResourcesShortageNotificationRuleTriggerConfig> {
@Override
public boolean matchesFilter(ResourcesShortageTrigger trigger, ResourcesShortageNotificationRuleTriggerConfig triggerConfig) {
float usagePercent = trigger.getUsage() / 100.0f;
return switch (trigger.getResource()) {
case CPU -> usagePercent >= triggerConfig.getCpuThreshold();
case RAM -> usagePercent >= triggerConfig.getRamThreshold();
case STORAGE -> usagePercent >= triggerConfig.getStorageThreshold();
};
}
@Override
public RuleOriginatedNotificationInfo constructNotificationInfo(ResourcesShortageTrigger trigger) {
return ResourcesShortageNotificationInfo.builder().resource(trigger.getResource().name()).usage(trigger.getUsage()).build();
}
@Override
public NotificationRuleTriggerType getTriggerType() {
return NotificationRuleTriggerType.RESOURCES_SHORTAGE;
}
}

22
application/src/main/java/org/thingsboard/server/service/system/DefaultSystemInfoService.java

@ -39,6 +39,9 @@ import org.thingsboard.server.common.data.kv.BooleanDataEntry;
import org.thingsboard.server.common.data.kv.JsonDataEntry; import org.thingsboard.server.common.data.kv.JsonDataEntry;
import org.thingsboard.server.common.data.kv.LongDataEntry; import org.thingsboard.server.common.data.kv.LongDataEntry;
import org.thingsboard.server.common.data.kv.TsKvEntry; import org.thingsboard.server.common.data.kv.TsKvEntry;
import org.thingsboard.server.common.data.notification.rule.trigger.ResourcesShortageTrigger;
import org.thingsboard.server.common.data.notification.rule.trigger.ResourcesShortageTrigger.Resource;
import org.thingsboard.server.common.msg.notification.NotificationRuleProcessor;
import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.common.msg.queue.ServiceType;
import org.thingsboard.server.common.stats.TbApiUsageStateClient; import org.thingsboard.server.common.stats.TbApiUsageStateClient;
import org.thingsboard.server.dao.domain.DomainService; import org.thingsboard.server.dao.domain.DomainService;
@ -92,6 +95,7 @@ public class DefaultSystemInfoService extends TbApplicationEventListener<Partiti
private final DomainService domainService; private final DomainService domainService;
private final MailService mailService; private final MailService mailService;
private final SmsService smsService; private final SmsService smsService;
private final NotificationRuleProcessor notificationRule;
private volatile ScheduledExecutorService scheduler; private volatile ScheduledExecutorService scheduler;
@Value("${metrics.system_info.persist_frequency:60}") @Value("${metrics.system_info.persist_frequency:60}")
@ -163,7 +167,7 @@ public class DefaultSystemInfoService extends TbApplicationEventListener<Partiti
if (twoFaSettings != null) { if (twoFaSettings != null) {
var providers = twoFaSettings.getJsonValue().get("providers"); var providers = twoFaSettings.getJsonValue().get("providers");
if (providers != null) { if (providers != null) {
return providers.size() > 0; return !providers.isEmpty();
} }
} }
return false; return false;
@ -188,9 +192,18 @@ public class DefaultSystemInfoService extends TbApplicationEventListener<Partiti
long ts = System.currentTimeMillis(); long ts = System.currentTimeMillis();
List<TsKvEntry> tsList = new ArrayList<>(); List<TsKvEntry> tsList = new ArrayList<>();
tsList.add(new BasicTsKvEntry(ts, new BooleanDataEntry("clusterMode", false))); tsList.add(new BasicTsKvEntry(ts, new BooleanDataEntry("clusterMode", false)));
getCpuUsage().ifPresent(v -> tsList.add(new BasicTsKvEntry(ts, new LongDataEntry("cpuUsage", (long) v)))); getCpuUsage().ifPresent(v -> {
getMemoryUsage().ifPresent(v -> tsList.add(new BasicTsKvEntry(ts, new LongDataEntry("memoryUsage", (long) v)))); tsList.add(new BasicTsKvEntry(ts, new LongDataEntry("cpuUsage", (long) v)));
getDiscSpaceUsage().ifPresent(v -> tsList.add(new BasicTsKvEntry(ts, new LongDataEntry("discUsage", (long) v)))); notificationRule.process(ResourcesShortageTrigger.builder().resource(Resource.CPU).usage(v).build());
});
getMemoryUsage().ifPresent(v -> {
tsList.add(new BasicTsKvEntry(ts, new LongDataEntry("memoryUsage", (long) v)));
notificationRule.process(ResourcesShortageTrigger.builder().resource(Resource.RAM).usage(v).build());
});
getDiscSpaceUsage().ifPresent(v -> {
tsList.add(new BasicTsKvEntry(ts, new LongDataEntry("discUsage", (long) v)));
notificationRule.process(ResourcesShortageTrigger.builder().resource(Resource.STORAGE).usage(v).build());
});
getCpuCount().ifPresent(v -> tsList.add(new BasicTsKvEntry(ts, new LongDataEntry("cpuCount", (long) v)))); getCpuCount().ifPresent(v -> tsList.add(new BasicTsKvEntry(ts, new LongDataEntry("cpuCount", (long) v))));
getTotalMemory().ifPresent(v -> tsList.add(new BasicTsKvEntry(ts, new LongDataEntry("totalMemory", v)))); getTotalMemory().ifPresent(v -> tsList.add(new BasicTsKvEntry(ts, new LongDataEntry("totalMemory", v))));
@ -244,4 +257,5 @@ public class DefaultSystemInfoService extends TbApplicationEventListener<Partiti
scheduler = null; scheduler = null;
} }
} }
} }

3
common/data/src/main/java/org/thingsboard/server/common/data/notification/NotificationType.java

@ -37,7 +37,8 @@ public enum NotificationType {
RATE_LIMITS, RATE_LIMITS,
EDGE_CONNECTION, EDGE_CONNECTION,
EDGE_COMMUNICATION_FAILURE, EDGE_COMMUNICATION_FAILURE,
TASK_PROCESSING_FAILURE; TASK_PROCESSING_FAILURE,
RESOURCES_SHORTAGE;
@Getter @Getter
private boolean system; // for future use and compatibility with PE private boolean system; // for future use and compatibility with PE

42
common/data/src/main/java/org/thingsboard/server/common/data/notification/info/ResourcesShortageNotificationInfo.java

@ -0,0 +1,42 @@
/**
* Copyright © 2016-2024 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.notification.info;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Map;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class ResourcesShortageNotificationInfo implements RuleOriginatedNotificationInfo {
private String resource;
private Integer usage;
@Override
public Map<String, String> getTemplateData() {
return Map.of(
"resource", resource,
"usage", String.valueOf(usage)
);
}
}

5
common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/NewPlatformVersionTrigger.java

@ -55,9 +55,4 @@ public class NewPlatformVersionTrigger implements NotificationRuleTrigger {
updateInfo.getCurrentVersion(), updateInfo.getLatestVersion()); updateInfo.getCurrentVersion(), updateInfo.getLatestVersion());
} }
@Override
public long getDefaultDeduplicationDuration() {
return 0;
}
} }

71
common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/ResourcesShortageTrigger.java

@ -0,0 +1,71 @@
/**
* Copyright © 2016-2024 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.notification.rule.trigger;
import lombok.Builder;
import lombok.Data;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.notification.rule.trigger.config.NotificationRuleTriggerType;
import java.io.Serial;
import java.util.concurrent.TimeUnit;
@Data
@Builder
public class ResourcesShortageTrigger implements NotificationRuleTrigger {
@Serial
private static final long serialVersionUID = 6024216015202949570L;
private Resource resource;
private Integer usage;
@Override
public TenantId getTenantId() {
return TenantId.SYS_TENANT_ID;
}
@Override
public EntityId getOriginatorEntityId() {
return TenantId.SYS_TENANT_ID;
}
@Override
public boolean deduplicate() {
return true;
}
@Override
public String getDeduplicationKey() {
return resource.name();
}
@Override
public long getDefaultDeduplicationDuration() {
return TimeUnit.HOURS.toMillis(1);
}
@Override
public NotificationRuleTriggerType getType() {
return NotificationRuleTriggerType.RESOURCES_SHORTAGE;
}
public enum Resource {
CPU, RAM, STORAGE
}
}

10
common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/TaskProcessingFailureTrigger.java

@ -22,10 +22,15 @@ import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.notification.rule.trigger.config.NotificationRuleTriggerType; import org.thingsboard.server.common.data.notification.rule.trigger.config.NotificationRuleTriggerType;
import java.io.Serial;
@Data @Data
@Builder @Builder
public class TaskProcessingFailureTrigger implements NotificationRuleTrigger { public class TaskProcessingFailureTrigger implements NotificationRuleTrigger {
@Serial
private static final long serialVersionUID = 5606203770553105345L;
private final HousekeeperTask task; private final HousekeeperTask task;
private final int attempt; private final int attempt;
private final Throwable error; private final Throwable error;
@ -45,9 +50,4 @@ public class TaskProcessingFailureTrigger implements NotificationRuleTrigger {
return task.getEntityId(); return task.getEntityId();
} }
@Override
public boolean deduplicate() {
return false;
}
} }

3
common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/config/NotificationRuleTriggerConfig.java

@ -38,7 +38,8 @@ import java.io.Serializable;
@Type(value = RateLimitsNotificationRuleTriggerConfig.class, name = "RATE_LIMITS"), @Type(value = RateLimitsNotificationRuleTriggerConfig.class, name = "RATE_LIMITS"),
@Type(value = EdgeConnectionNotificationRuleTriggerConfig.class, name = "EDGE_CONNECTION"), @Type(value = EdgeConnectionNotificationRuleTriggerConfig.class, name = "EDGE_CONNECTION"),
@Type(value = EdgeCommunicationFailureNotificationRuleTriggerConfig.class, name = "EDGE_COMMUNICATION_FAILURE"), @Type(value = EdgeCommunicationFailureNotificationRuleTriggerConfig.class, name = "EDGE_COMMUNICATION_FAILURE"),
@Type(value = TaskProcessingFailureNotificationRuleTriggerConfig.class, name = "TASK_PROCESSING_FAILURE") @Type(value = TaskProcessingFailureNotificationRuleTriggerConfig.class, name = "TASK_PROCESSING_FAILURE"),
@Type(value = ResourcesShortageNotificationRuleTriggerConfig.class, name = "RESOURCES_SHORTAGE")
}) })
public interface NotificationRuleTriggerConfig extends Serializable { public interface NotificationRuleTriggerConfig extends Serializable {

3
common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/config/NotificationRuleTriggerType.java

@ -32,7 +32,8 @@ public enum NotificationRuleTriggerType {
ENTITIES_LIMIT(false), ENTITIES_LIMIT(false),
API_USAGE_LIMIT(false), API_USAGE_LIMIT(false),
RATE_LIMITS(false), RATE_LIMITS(false),
TASK_PROCESSING_FAILURE(false); TASK_PROCESSING_FAILURE(false),
RESOURCES_SHORTAGE(false);
private final boolean tenantLevel; private final boolean tenantLevel;

48
common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/config/ResourcesShortageNotificationRuleTriggerConfig.java

@ -0,0 +1,48 @@
/**
* Copyright © 2016-2024 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.notification.rule.trigger.config;
import jakarta.validation.constraints.Max;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serial;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class ResourcesShortageNotificationRuleTriggerConfig implements NotificationRuleTriggerConfig {
@Serial
private static final long serialVersionUID = 339395299693241424L;
private String resource;
@Max(1)
private float cpuThreshold; // in percents
@Max(1)
private float ramThreshold; // in percents
@Max(1)
private float storageThreshold; // in percents
@Override
public NotificationRuleTriggerType getTriggerType() {
return NotificationRuleTriggerType.RESOURCES_SHORTAGE;
}
}

4
dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationSettingsService.java

@ -186,6 +186,7 @@ public class DefaultNotificationSettingsService implements NotificationSettingsS
defaultNotifications.create(tenantId, DefaultNotifications.exceededRateLimitsForSysadmin, sysAdmins.getId()); defaultNotifications.create(tenantId, DefaultNotifications.exceededRateLimitsForSysadmin, sysAdmins.getId());
defaultNotifications.create(tenantId, DefaultNotifications.newPlatformVersion, sysAdmins.getId()); defaultNotifications.create(tenantId, DefaultNotifications.newPlatformVersion, sysAdmins.getId());
defaultNotifications.create(tenantId, DefaultNotifications.taskProcessingFailure, tenantAdmins.getId()); defaultNotifications.create(tenantId, DefaultNotifications.taskProcessingFailure, tenantAdmins.getId());
defaultNotifications.create(tenantId, DefaultNotifications.resourcesShortage, sysAdmins.getId());
return; return;
} }
@ -221,6 +222,9 @@ public class DefaultNotificationSettingsService implements NotificationSettingsS
if (!isNotificationConfigured(tenantId, NotificationType.TASK_PROCESSING_FAILURE)) { if (!isNotificationConfigured(tenantId, NotificationType.TASK_PROCESSING_FAILURE)) {
defaultNotifications.create(tenantId, DefaultNotifications.taskProcessingFailure, sysAdmins.getId()); defaultNotifications.create(tenantId, DefaultNotifications.taskProcessingFailure, sysAdmins.getId());
} }
if (!isNotificationConfigured(tenantId, NotificationType.RESOURCES_SHORTAGE)) {
defaultNotifications.create(tenantId, DefaultNotifications.resourcesShortage, sysAdmins.getId());
}
} else { } else {
var requiredNotificationTypes = List.of(NotificationType.EDGE_CONNECTION, NotificationType.EDGE_COMMUNICATION_FAILURE); var requiredNotificationTypes = List.of(NotificationType.EDGE_CONNECTION, NotificationType.EDGE_COMMUNICATION_FAILURE);
var existingNotificationTypes = notificationTemplateService.findNotificationTemplatesByTenantIdAndNotificationTypes( var existingNotificationTypes = notificationTemplateService.findNotificationTemplatesByTenantIdAndNotificationTypes(

16
dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotifications.java

@ -33,6 +33,7 @@ import org.thingsboard.server.common.data.notification.rule.DefaultNotificationR
import org.thingsboard.server.common.data.notification.rule.EscalatedNotificationRuleRecipientsConfig; import org.thingsboard.server.common.data.notification.rule.EscalatedNotificationRuleRecipientsConfig;
import org.thingsboard.server.common.data.notification.rule.NotificationRule; import org.thingsboard.server.common.data.notification.rule.NotificationRule;
import org.thingsboard.server.common.data.notification.rule.NotificationRuleConfig; import org.thingsboard.server.common.data.notification.rule.NotificationRuleConfig;
import org.thingsboard.server.common.data.notification.rule.trigger.ResourcesShortageTrigger.Resource;
import org.thingsboard.server.common.data.notification.rule.trigger.config.AlarmAssignmentNotificationRuleTriggerConfig; import org.thingsboard.server.common.data.notification.rule.trigger.config.AlarmAssignmentNotificationRuleTriggerConfig;
import org.thingsboard.server.common.data.notification.rule.trigger.config.AlarmCommentNotificationRuleTriggerConfig; import org.thingsboard.server.common.data.notification.rule.trigger.config.AlarmCommentNotificationRuleTriggerConfig;
import org.thingsboard.server.common.data.notification.rule.trigger.config.AlarmNotificationRuleTriggerConfig; import org.thingsboard.server.common.data.notification.rule.trigger.config.AlarmNotificationRuleTriggerConfig;
@ -49,6 +50,7 @@ import org.thingsboard.server.common.data.notification.rule.trigger.config.NewPl
import org.thingsboard.server.common.data.notification.rule.trigger.config.NotificationRuleTriggerConfig; import org.thingsboard.server.common.data.notification.rule.trigger.config.NotificationRuleTriggerConfig;
import org.thingsboard.server.common.data.notification.rule.trigger.config.NotificationRuleTriggerType; import org.thingsboard.server.common.data.notification.rule.trigger.config.NotificationRuleTriggerType;
import org.thingsboard.server.common.data.notification.rule.trigger.config.RateLimitsNotificationRuleTriggerConfig; import org.thingsboard.server.common.data.notification.rule.trigger.config.RateLimitsNotificationRuleTriggerConfig;
import org.thingsboard.server.common.data.notification.rule.trigger.config.ResourcesShortageNotificationRuleTriggerConfig;
import org.thingsboard.server.common.data.notification.rule.trigger.config.RuleEngineComponentLifecycleEventNotificationRuleTriggerConfig; import org.thingsboard.server.common.data.notification.rule.trigger.config.RuleEngineComponentLifecycleEventNotificationRuleTriggerConfig;
import org.thingsboard.server.common.data.notification.rule.trigger.config.TaskProcessingFailureNotificationRuleTriggerConfig; import org.thingsboard.server.common.data.notification.rule.trigger.config.TaskProcessingFailureNotificationRuleTriggerConfig;
import org.thingsboard.server.common.data.notification.template.NotificationTemplate; import org.thingsboard.server.common.data.notification.template.NotificationTemplate;
@ -391,6 +393,20 @@ public class DefaultNotifications {
.color(RED_COLOR) .color(RED_COLOR)
.build(); .build();
public static final DefaultNotification resourcesShortage = DefaultNotification.builder()
.name("Resources shortage notification")
.type(NotificationType.RESOURCES_SHORTAGE)
.subject("Warning: ${resource} shortage")
.text("The ${resource} usage is on the rise (currently at ${usage}%). Immediate action required to prevent system instability.")
.icon("warning")
.rule(DefaultRule.builder()
.name("Resources shortage")
.triggerConfig(ResourcesShortageNotificationRuleTriggerConfig.builder().resource(Resource.CPU.name()).cpuThreshold(90).storageThreshold(90).ramThreshold(90).build())
.description("Send notification to system admins when resources shortage is running low")
.build())
.color(RED_COLOR)
.build();
private final NotificationTemplateService templateService; private final NotificationTemplateService templateService;
private final NotificationRuleService ruleService; private final NotificationRuleService ruleService;

60
ui-ngx/src/app/modules/home/pages/notification/rule/rule-notification-dialog.component.html

@ -591,6 +591,66 @@
</section> </section>
</form> </form>
</mat-step> </mat-step>
<mat-step *ngIf="ruleNotificationForm.get('triggerType').value === triggerType.RESOURCES_SHORTAGE"
[stepControl]="resourceUsageShortageTemplateForm">
<ng-template matStepLabel>{{ 'notification.resources-shortage-trigger-settings' | translate }}</ng-template>
<form [formGroup]="resourceUsageShortageTemplateForm">
<fieldset class="fields-group tb-margin" formGroupName="triggerConfig">
<legend translate>notification.filter</legend>
<div class="limit-slider-container flex flex-row items-center justify-start xs:flex-col xs:items-stretch">
<label translate>notification.cpu-threshold</label>
<div class="flex flex-1 flex-row items-center justify-start">
<mat-slider class="flex-1" min="0" max="1" step="0.01" discrete [displayWith]="formatLabel">
<input matSliderThumb formControlName="cpuThreshold">
</mat-slider>
<mat-form-field class="limit-slider-value">
<input matInput formControlName="cpuThreshold" type="number" step="0.01"
[value]="resourceUsageShortageTemplateForm.get('triggerConfig.cpuThreshold').value"
min="0"
max="1"/>
</mat-form-field>
</div>
</div>
<div class="limit-slider-container flex flex-row items-center justify-start xs:flex-col xs:items-stretch">
<label translate>notification.ram-threshold</label>
<div class="flex flex-1 flex-row items-center justify-start">
<mat-slider class="flex-1" min="0" max="1" step="0.01" discrete [displayWith]="formatLabel">
<input matSliderThumb formControlName="ramThreshold">
</mat-slider>
<mat-form-field class="limit-slider-value">
<input matInput formControlName="ramThreshold" type="number" step="0.01"
[value]="resourceUsageShortageTemplateForm.get('triggerConfig.ramThreshold').value"
min="0"
max="1"/>
</mat-form-field>
</div>
</div>
<div class="limit-slider-container flex flex-row items-center justify-start xs:flex-col xs:items-stretch">
<label translate>notification.storage-threshold</label>
<div class="flex flex-1 flex-row items-center justify-start">
<mat-slider class="flex-1" min="0" max="1" step="0.01" discrete [displayWith]="formatLabel">
<input matSliderThumb formControlName="storageThreshold">
</mat-slider>
<mat-form-field class="limit-slider-value">
<input matInput formControlName="storageThreshold" type="number" step="0.01"
[value]="resourceUsageShortageTemplateForm.get('triggerConfig.storageThreshold').value"
min="0"
max="1"/>
</mat-form-field>
</div>
</div>
</fieldset>
</form>
<form [formGroup]="ruleNotificationForm">
<section formGroupName="additionalConfig">
<mat-form-field class="mat-block">
<mat-label translate>notification.description</mat-label>
<input matInput formControlName="description">
</mat-form-field>
</section>
</form>
</mat-step>
</mat-horizontal-stepper> </mat-horizontal-stepper>
</div> </div>
<mat-divider></mat-divider> <mat-divider></mat-divider>

15
ui-ngx/src/app/modules/home/pages/notification/rule/rule-notification-dialog.component.ts

@ -102,6 +102,7 @@ export class RuleNotificationDialogComponent extends
edgeCommunicationFailureTemplateForm: FormGroup; edgeCommunicationFailureTemplateForm: FormGroup;
edgeConnectionTemplateForm: FormGroup; edgeConnectionTemplateForm: FormGroup;
taskProcessingFailureTemplateForm: FormGroup; taskProcessingFailureTemplateForm: FormGroup;
resourceUsageShortageTemplateForm: FormGroup;
triggerType = TriggerType; triggerType = TriggerType;
triggerTypes: TriggerType[]; triggerTypes: TriggerType[];
@ -344,6 +345,14 @@ export class RuleNotificationDialogComponent extends
}) })
}); });
this.resourceUsageShortageTemplateForm = this.fb.group({
triggerConfig: this.fb.group({
cpuThreshold: [.9, [Validators.min(0), Validators.max(1)]],
ramThreshold: [.9, [Validators.min(0), Validators.max(1)]],
storageThreshold: [.9, [Validators.min(0), Validators.max(1)]]
})
});
this.triggerTypeFormsMap = new Map<TriggerType, FormGroup>([ this.triggerTypeFormsMap = new Map<TriggerType, FormGroup>([
[TriggerType.ALARM, this.alarmTemplateForm], [TriggerType.ALARM, this.alarmTemplateForm],
[TriggerType.ALARM_COMMENT, this.alarmCommentTemplateForm], [TriggerType.ALARM_COMMENT, this.alarmCommentTemplateForm],
@ -357,7 +366,8 @@ export class RuleNotificationDialogComponent extends
[TriggerType.RATE_LIMITS, this.rateLimitsTemplateForm], [TriggerType.RATE_LIMITS, this.rateLimitsTemplateForm],
[TriggerType.EDGE_COMMUNICATION_FAILURE, this.edgeCommunicationFailureTemplateForm], [TriggerType.EDGE_COMMUNICATION_FAILURE, this.edgeCommunicationFailureTemplateForm],
[TriggerType.EDGE_CONNECTION, this.edgeConnectionTemplateForm], [TriggerType.EDGE_CONNECTION, this.edgeConnectionTemplateForm],
[TriggerType.TASK_PROCESSING_FAILURE, this.taskProcessingFailureTemplateForm] [TriggerType.TASK_PROCESSING_FAILURE, this.taskProcessingFailureTemplateForm],
[TriggerType.RESOURCES_SHORTAGE, this.resourceUsageShortageTemplateForm]
]); ]);
if (data.isAdd || data.isCopy) { if (data.isAdd || data.isCopy) {
@ -497,7 +507,8 @@ export class RuleNotificationDialogComponent extends
TriggerType.API_USAGE_LIMIT, TriggerType.API_USAGE_LIMIT,
TriggerType.NEW_PLATFORM_VERSION, TriggerType.NEW_PLATFORM_VERSION,
TriggerType.RATE_LIMITS, TriggerType.RATE_LIMITS,
TriggerType.TASK_PROCESSING_FAILURE TriggerType.TASK_PROCESSING_FAILURE,
TriggerType.RESOURCES_SHORTAGE
]); ]);
if (this.isSysAdmin()) { if (this.isSysAdmin()) {

3
ui-ngx/src/app/modules/home/pages/notification/template/template-notification-dialog.component.ts

@ -180,7 +180,8 @@ export class TemplateNotificationDialogComponent
NotificationType.API_USAGE_LIMIT, NotificationType.API_USAGE_LIMIT,
NotificationType.NEW_PLATFORM_VERSION, NotificationType.NEW_PLATFORM_VERSION,
NotificationType.RATE_LIMITS, NotificationType.RATE_LIMITS,
NotificationType.TASK_PROCESSING_FAILURE NotificationType.TASK_PROCESSING_FAILURE,
NotificationType.RESOURCES_SHORTAGE
]); ]);
if (this.isSysAdmin()) { if (this.isSysAdmin()) {

16
ui-ngx/src/app/shared/models/notification.models.ts

@ -526,7 +526,8 @@ export enum NotificationType {
RATE_LIMITS = 'RATE_LIMITS', RATE_LIMITS = 'RATE_LIMITS',
EDGE_CONNECTION = 'EDGE_CONNECTION', EDGE_CONNECTION = 'EDGE_CONNECTION',
EDGE_COMMUNICATION_FAILURE = 'EDGE_COMMUNICATION_FAILURE', EDGE_COMMUNICATION_FAILURE = 'EDGE_COMMUNICATION_FAILURE',
TASK_PROCESSING_FAILURE = 'TASK_PROCESSING_FAILURE' TASK_PROCESSING_FAILURE = 'TASK_PROCESSING_FAILURE',
RESOURCES_SHORTAGE = 'RESOURCES_SHORTAGE'
} }
export const NotificationTypeIcons = new Map<NotificationType, string | null>([ export const NotificationTypeIcons = new Map<NotificationType, string | null>([
@ -538,7 +539,8 @@ export const NotificationTypeIcons = new Map<NotificationType, string | null>([
[NotificationType.RULE_ENGINE_COMPONENT_LIFECYCLE_EVENT, 'settings_ethernet'], [NotificationType.RULE_ENGINE_COMPONENT_LIFECYCLE_EVENT, 'settings_ethernet'],
[NotificationType.ENTITIES_LIMIT, 'data_thresholding'], [NotificationType.ENTITIES_LIMIT, 'data_thresholding'],
[NotificationType.API_USAGE_LIMIT, 'insert_chart'], [NotificationType.API_USAGE_LIMIT, 'insert_chart'],
[NotificationType.TASK_PROCESSING_FAILURE, 'warning'] [NotificationType.TASK_PROCESSING_FAILURE, 'warning'],
[NotificationType.RESOURCES_SHORTAGE, 'warning']
]); ]);
export const AlarmSeverityNotificationColors = new Map<AlarmSeverity, string>( export const AlarmSeverityNotificationColors = new Map<AlarmSeverity, string>(
@ -657,6 +659,12 @@ export const NotificationTemplateTypeTranslateMap = new Map<NotificationType, No
helpId: 'notification/task_processing_failure' helpId: 'notification/task_processing_failure'
} }
], ],
[NotificationType.RESOURCES_SHORTAGE,
{
name: 'notification.template-type.resources-shortage',
helpId: 'notification/resources_shortage'
}
]
]); ]);
export enum TriggerType { export enum TriggerType {
@ -673,6 +681,7 @@ export enum TriggerType {
EDGE_CONNECTION = 'EDGE_CONNECTION', EDGE_CONNECTION = 'EDGE_CONNECTION',
EDGE_COMMUNICATION_FAILURE = 'EDGE_COMMUNICATION_FAILURE', EDGE_COMMUNICATION_FAILURE = 'EDGE_COMMUNICATION_FAILURE',
TASK_PROCESSING_FAILURE = 'TASK_PROCESSING_FAILURE', TASK_PROCESSING_FAILURE = 'TASK_PROCESSING_FAILURE',
RESOURCES_SHORTAGE = 'RESOURCES_SHORTAGE'
} }
export const TriggerTypeTranslationMap = new Map<TriggerType, string>([ export const TriggerTypeTranslationMap = new Map<TriggerType, string>([
@ -688,7 +697,8 @@ export const TriggerTypeTranslationMap = new Map<TriggerType, string>([
[TriggerType.RATE_LIMITS, 'notification.trigger.rate-limits'], [TriggerType.RATE_LIMITS, 'notification.trigger.rate-limits'],
[TriggerType.EDGE_CONNECTION, 'notification.trigger.edge-connection'], [TriggerType.EDGE_CONNECTION, 'notification.trigger.edge-connection'],
[TriggerType.EDGE_COMMUNICATION_FAILURE, 'notification.trigger.edge-communication-failure'], [TriggerType.EDGE_COMMUNICATION_FAILURE, 'notification.trigger.edge-communication-failure'],
[TriggerType.TASK_PROCESSING_FAILURE, 'notification.trigger.task-processing-failure'] [TriggerType.TASK_PROCESSING_FAILURE, 'notification.trigger.task-processing-failure'],
[TriggerType.RESOURCES_SHORTAGE, 'notification.trigger.resources-shortage']
]); ]);
export interface NotificationUserSettings { export interface NotificationUserSettings {

42
ui-ngx/src/assets/help/en_US/notification/resources_shortage.md

@ -0,0 +1,42 @@
#### Resource usage shortage notification templatization
<div class="divider"></div>
<br/>
Notification subject and message fields support templatization.
The list of available templatization parameters depends on the template type.
See the available types and parameters below:
Available template parameters:
* `cpuThreshold` - the CPU shortage threshold;
* `ramThreshold` - the RAM shortage threshold;
* `storageThreshold` - the Storage shortage threshold;
Parameter names must be wrapped using `${...}`. For example: `${entityType}`.
You may also modify the value of the parameter with one of the suffixes:
* `upperCase`, for example - `${entityType:upperCase}`
* `lowerCase`, for example - `${entityType:lowerCase}`
* `capitalize`, for example - `${entityType:capitalize}`
<div class="divider"></div>
##### Examples
Let's assume there is a resource usage shortage and the system is low on free resources (CPU, RAM, or Storage).
The following template:
```text
Warning: ${resource} is critically high at ${usage}%
{:copy-code}
```
will be transformed to:
```text
Warning: CPU is critically high at 83%
```
<br>
<br>

8
ui-ngx/src/assets/locale/locale.constant-en_US.json

@ -3728,6 +3728,7 @@
"new-platform-version-trigger-settings": "New platform version trigger settings", "new-platform-version-trigger-settings": "New platform version trigger settings",
"rate-limits-trigger-settings": "Exceeded rate limits trigger settings", "rate-limits-trigger-settings": "Exceeded rate limits trigger settings",
"task-processing-failure-trigger-settings": "Task processing failure trigger settings", "task-processing-failure-trigger-settings": "Task processing failure trigger settings",
"resources-shortage-trigger-settings": "Resources shortage trigger settings",
"at-least-one-should-be-selected": "At least one should be selected", "at-least-one-should-be-selected": "At least one should be selected",
"basic-settings": "Basic settings", "basic-settings": "Basic settings",
"button-text": "Button text", "button-text": "Button text",
@ -3742,6 +3743,7 @@
"create-new": "Create new", "create-new": "Create new",
"created": "Created", "created": "Created",
"customize-messages": "Customize messages", "customize-messages": "Customize messages",
"cpu-threshold": "CPU threshold",
"delete-notification-text": "Be careful, after the confirmation the notification will become unrecoverable.", "delete-notification-text": "Be careful, after the confirmation the notification will become unrecoverable.",
"delete-notification-title": "Are you sure you want to delete the notification?", "delete-notification-title": "Are you sure you want to delete the notification?",
"delete-notifications-text": "Be careful, after the confirmation notifications will become unrecoverable.", "delete-notifications-text": "Be careful, after the confirmation notifications will become unrecoverable.",
@ -3857,6 +3859,7 @@
"only-rule-chain-lifecycle-failures": "Only rule chain lifecycle failures", "only-rule-chain-lifecycle-failures": "Only rule chain lifecycle failures",
"only-rule-node-lifecycle-failures": "Only rule node lifecycle failures", "only-rule-node-lifecycle-failures": "Only rule node lifecycle failures",
"platform-users": "Platform users", "platform-users": "Platform users",
"ram-threshold": "RAM threshold",
"rate-limits": "Rate limits", "rate-limits": "Rate limits",
"rate-limits-hint": "If the field is empty, the trigger will be applied to all rate limits", "rate-limits-hint": "If the field is empty, the trigger will be applied to all rate limits",
"recipient": "Recipient", "recipient": "Recipient",
@ -3922,6 +3925,7 @@
"start-from-scratch": "Start from scratch", "start-from-scratch": "Start from scratch",
"status": "Status", "status": "Status",
"stop-escalation-alarm-status-become": "Stop the escalation on the alarm status become:", "stop-escalation-alarm-status-become": "Stop the escalation on the alarm status become:",
"storage-threshold": "Storage threshold",
"subject": "Subject", "subject": "Subject",
"subject-required": "Subject is required", "subject-required": "Subject is required",
"subject-max-length": "Subject should be less than or equal to {{ length }} characters", "subject-max-length": "Subject should be less than or equal to {{ length }} characters",
@ -3943,7 +3947,8 @@
"rate-limits": "Exceeded rate limits", "rate-limits": "Exceeded rate limits",
"edge-communication-failure": "Edge communication failure", "edge-communication-failure": "Edge communication failure",
"edge-connection": "Edge connection", "edge-connection": "Edge connection",
"task-processing-failure": "Task processing failure" "task-processing-failure": "Task processing failure",
"resources-shortage": "Resources shortage"
}, },
"templates": "Templates", "templates": "Templates",
"notification-templates": "Notifications / Templates", "notification-templates": "Notifications / Templates",
@ -3967,6 +3972,7 @@
"edge-connection": "Edge connection", "edge-connection": "Edge connection",
"edge-communication-failure": "Edge communication failure", "edge-communication-failure": "Edge communication failure",
"task-processing-failure": "Task processing failure", "task-processing-failure": "Task processing failure",
"resources-shortage": "Resources shortage",
"trigger": "Trigger", "trigger": "Trigger",
"trigger-required": "Trigger is required" "trigger-required": "Trigger is required"
}, },

Loading…
Cancel
Save