Define alarms silencing rules with collections¶
Prerequisites¶
git checkout origin/osp-alarms-web-configuration .
git checkout origin/osp-collections-configuration .
Description¶
In this tutorial, we will go through every necessary step to set up a silencing process for any upcoming alarm.
We will use a collection to represent a list of silencing rules. Then, upon receiving an alarm, we check if the alarm match any one of these rules and, if it is the case, set the hideUntil property of the alarm to silence it until the stop timestamp provided by the rule.
We are going to create the collection first, create some rules on it and finally define a pre insertion rule to check an incoming alarm. We will have a dashboard as well to display the rules collection and an alarm table to see the result of our work.
This tutorial doesn’t contain any generation script or anything alike to generate some alarms. You can follow one of the other alarms examples to set an alarm generator to test this tutorial.
This tutorial also assumes that you have a basic understanding of collections and how to create one, as we are not going to go through every detail when creating the rules collection here. If it isn’t the case, you should start by reading the collections feature documentation and go through the Define a collection example first.
Warning
Please be aware that this example is very naive at times and should not be used as a one-to-one implementation of what you could need depending on your specific needs. The purpose of this is only to demonstrate that the functionality can be implemented, but we still expect of you that you make changes when necessary.
Steps¶
1. Define the collection¶
In this example, a rule is mainly composed of a filter
that will define if the alarm is affected by the rule or not and an hideUntil
date that will mark the time an alarm is hided. After that date, the alarm will be visible. To complete the collection, we added a summary
and an isActive
field, but these are not mandatory for the purpose we want to achieve. We will later use the isActive field to define the filter used when retrieving the rules when handling the upcoming alarms, but you could totally use a global filter and retrieve every entry of the collection.
Schema
The filter property in the schema must be described with the following property:
field
: field of the alarm (i.e. severity, location, firstTimestamp, ….)operation
: operation of the filter. Look below for the full list of available operation.content
: value to compare to.
The schema for this collection should look like this:
root/silencing/collections/rules/schema.ospp
{
"filters": [
{
"id": "all",
"name": "All"
},
{
"id": "isActive",
"name": "Is active"
}
],
"schema": {
"type": "object",
"properties": {
"summary": {
"type": "string",
"title": "Summary"
},
"isActive": {
"title": "State",
"type": "boolean"
},
"hideUntil": {
"type": "number",
"title": "Hide until",
"$comment": "date"
},
"filter": {
"type": "object",
"properties": {
"field": {
"type": "string"
},
"operation": {
"type": "string",
"enum": [
"EQUAL",
"NOT_EQUAL",
"GREATER_THAN",
"GREATER_THAN_EQUAL",
"LESS_THAN",
"LESS_THAN_EQUAL",
"SIZE_EQUAL",
"SIZE_NOT_EQUAL",
"SIZE_GREATER_THAN",
"SIZE_GREATER_THAN_EQUAL",
"SIZE_LESS_THAN",
"SIZE_LESS_THAN_EQUAL",
"CONTAIN",
"NOT_CONTAIN",
"START_WITH",
"END_WITH",
"NEWER_THAN",
"NEWER_THAN_EQUAL",
"OLDER_THAN",
"OLDER_THAN_EQUAL",
"ARRAY_BETWEEN",
"OR",
"AND"
]
},
"content": {}
}
}
}
}
}
For the schema.web and schema.collections file, there isn’t any noteworthy element. You can declare them with the minimum required information.
root/silencing/collections/rules/schema.collections
{
"moduleId": "modules.collections.collections-1",
"collectionName": "silencing_rules",
"indexes": [
{
"name": "summary",
"index": "{'summary': 1}"
},
{
"name": "isActive",
"index": "{'isActive': 1}"
},
{
"name": "hideUntil",
"index": "{'hideUntil': 1}"
}
],
"filters": [
{
"id": "isActive",
"query": "{isActive: true}"
},
{
"id": "all",
"query": "{}"
}
]
}
root/silencing/collections/rules/schema.web
{
"moduleId": "modules.web.web-1",
"name": "Silencing rules",
"views": [
{
"id": "1",
"name": "Default",
"reorderable": true,
"isDefault": true,
"sort": [
{
"field": "hideUntil",
"direction": "desc"
}
],
"columns": [
{
"name": "Summary",
"field": "summary",
"position": 0
},
{
"name": "Is active",
"field": "isActive",
"position": 1,
"render": "BOOLEAN"
},
{
"name": "Hide until",
"field": "hideUntil",
"position": 2,
"render": "TIMESTAMP"
}
]
}
]
}
Form
As you may have realized, filter here is an object, not an array. Which means that only one filter can be define for one rule. Although, the AND
and OR
operation allow you to combine the result of multiple sub filters. If you want to define a rule with more than one filter, simply use a filter AND
or OR
as the root filter and add the others filters as sub filters.
In order to accomplish this in the front-end, there is a particular component that you can add to the form to build the filter, named AlarmsFilterBuilder. To use this component, we need to provide it a view. You can provide any view you want, but be aware that the fields the component can use are based on those declared in the liveColumns
property of the view. If an alarm property is not describe as a column there, you won’t be able to pick it in the filter component.
You can add the other schema properties in the form as you like. At the end, you should have something like:
root/silencing/collections/rules/form.web
{
"moduleId": [
"modules.web.web-1"
],
"name": "Silencing rules",
"description": "",
"bindings": {},
"rights": [],
"schema": "root.silencing.collections.rules",
"ui": {
"type": "VerticalLayout",
"elements": [
{
"type": "Group",
"elements": [
{
"type": "Control",
"scope": "#/properties/summary",
"label": "Summary"
},
{
"type": "Control",
"scope": "#/properties/isActive",
"label": "Is active"
},
{
"type": "Control",
"scope": "#/properties/hideUntil",
"options": {
"format": "date-time",
"autoFill": true
}
}
]
},
{
"type": "Group",
"elements": [
{
"type": "AlarmsFilterBuilder",
"scope": "#/properties/filter",
"label": "Filter",
"options": {
"view": "root.alarms.views.default"
}
}
]
}
]
},
"initialValue": {
"isActive": true
},
"submit": {
"destination": "Request",
"type": "Deferred"
}
}
2. Use a pre-insertion rule to handle upcoming alarms¶
Now that the collection exist, we can use it in a pre-insertion rule to check any upcoming alarm and modify it if needed before actually creating the alarm.
As stated in the pre-insertion rules documentation, there are different stages to follow, each one having a role to fulfill.
beginBatch
In this stage, we query the rules collection to fetch the rules and add them to a global variable to reuse them later on the next stages.
Warning
In this example, we assume that they aren’t more than an hundred element in the collection, which is a very naive approach. We remind you here that this example exist to demonstrate how this functionality could be implemented, but it’s still up to you to go the extra mile and complete it every time you feel it’s lacking for your needs.
1local SILENCE_RULES_COLLECTION_ID = "root.silencing.collections.rules"
2local SILENCE_RULES = nil
3
4local function initLocalSilencingRulesFromCollection()
5 local configuredRules = collections.list(SILENCE_RULES_COLLECTION_ID, 100, 0)
6 SILENCE_RULES = {}
7 for ruleIndex, rule in pairs(configuredRules.collections) do
8 table.insert(SILENCE_RULES, {_id= rule._id, summary=rule.summary, hideUntil=rule.hideUntil, filter=rule.filter, isActive=rule.isActive})
9 end
10end
22function retrieveSilenceRules(data)
23 if SILENCE_RULES == nil then
24 initLocalSilencingRulesFromCollection()
25 end
26end
for
In this stage, we need to define which alarm is impacted by this pre-insertion rule, meaning it is at this stage that we want to check if the alarm match any of the rules we got from the collection. To achieve this, we can use filters.match()
to compare the current alarm with one of the rules. If the result is positive, we add the rule to an array and if, after comparing with every rule, the size of the array is greater than 0, the alarm must be treated in the next stages.
12local function getRulesMatchingAlarm(alarm)
13 local matchingRules = {}
14 for _, silenceRule in pairs(SILENCE_RULES) do
15 if (filters.match(alarm, silenceRule.filter)) then
16 table.insert(matchingRules, silenceRule)
17 end
18 end
19 return matchingRules
20end
28function alarmMatchesAnySilencingRule(alarm)
29 local rulesMatchingAlarm = getRulesMatchingAlarm(alarm)
30 return (next(rulesMatchingAlarm) ~= nil)
31end
thenExecute
Now, for every alarm that match at least one of the rules, we compare every rule with each other to get the higher hideUntil
value and use that value to set the alarm hideUntil
property.
33function setHideUntil(alarm, data, operations)
34 local silencedAlarm = operations:create()
35 local rulesMatchingAlarm = getRulesMatchingAlarm(alarm)
36 local latestSilenceRequired = 0
37 for matchingRuleIndex, matchingRule in pairs(rulesMatchingAlarm) do
38 latestSilenceRequired = math.max(latestSilenceRequired, matchingRule.hideUntil)
39 end
40 silencedAlarm.hideUntil=latestSilenceRequired
41end
endBatch
At the end of the batch, we just reset the variable holding the collections rules.
43function clearSilenceRules()
44 SILENCE_RULES = nil
45end
Summary
With this pre-insertion rule, every new alarm will be given an hideUntil value if the alarm matches at least one of the rules set in our collection. Next step is to add a way to interact with the collection to create those rules.
3. Create a dashboard¶
You will now add a dashboard to use a Collection Table in order to define our rules. In the same dashboard, we will also add an Alarm Table to display the upcoming alarms.
There is nothing particular about the Collection Table we are going to add. On the other hand though, we need to define a new filter and a new view for the Alarm Table.
Alarm filter
By default, all filters have the flag ignoreHideUntil
set as true
, which means that even if an alarm has a hideUntil
value, it will still be displayed. We need to create a filter with at least that flag set as false
.
root/alarms/filters/all_without_hide_until/filter.alarms
{
"moduleId": "modules.alarms.alarms-1",
"query": "{}",
"ignoreHideUntil": false
}
Alarm view
We will create a new view too to add a column with the hideUntil
value, just so to have a visual confirmation of the actual hideUntil
value for each alarm.
root/alarms/views/default_with_hide_until/view.web
{
"moduleId": "modules.web.web-1",
"liveColumns": [
{
"name": "Acknowledged",
"display": false,
"render": "BOOLEAN",
"position": 0
},
{
"name": "Summary",
"position": 1,
"aggregate": "count"
},
{
"name": "Source",
"position": 2
},
{
"name": "Location",
"position": 3
},
{
"name": "Tags",
"render": "TAGS",
"position": 4
},
{
"name": "Severity",
"display": false,
"render": "SEVERITY",
"position": 5
},
{
"name": "Count",
"position": 6,
"aggregate": "sum"
},
{
"name": "Journal",
"display": false,
"render": "ARRAY_COUNT",
"position": 7
},
{
"name": "First occurrence",
"display": false,
"render": "TIMESTAMP",
"position": 8
},
{
"name": "Last occurrence",
"render": "TIMESTAMP",
"position": 9
},
{
"name": "Hide until",
"render": "TIMESTAMP",
"position": 10
}
],
"historyColumns": [
{
"name": "Acknowledged",
"display": false,
"render": "BOOLEAN",
"position": 0
},
{
"name": "Summary",
"position": 1,
"aggregate": "count"
},
{
"name": "Source",
"position": 2
},
{
"name": "Location",
"position": 3
},
{
"name": "Tags",
"render": "TAGS",
"position": 4
},
{
"name": "Journal",
"display": false,
"render": "ARRAY_COUNT",
"position": 5
},
{
"name": "Severity",
"display": false,
"render": "SEVERITY",
"position": 6
},
{
"name": "Timestamp",
"render": "TIMESTAMP",
"position": 7
},
{
"name": "Hide until",
"render": "TIMESTAMP",
"position": 8
}
],
"liveSort": [
{
"field": "lastTimestamp",
"direction": "desc"
}
],
"historySort": [
{
"field": "timestamp",
"direction": "desc"
}
]
}
Dashboard
All of this resulting in a dashboard that should look like something like this:
root/silencing/dashboard/dashboard.view
{
"configuration": [
{
"type": "AlarmTable",
"id": "E-ItOH43",
"title": "",
"menuReferences": [
"root.alarms.menus"
],
"alarmWidgetSettings": {
"defaultFilter": "root.alarms.filters.all_without_hide_until",
"defaultView": "root.alarms.views.default_with_hide_until",
"resizeMode": "widget",
"rowDetailHeight": 250,
"disableFilterUpdate": false,
"disableViewUpdate": false,
"disableToolbar": false,
"disableToolbarMenu": false,
"enableAutomaticRefresh": true,
"disableToolbarTableRefresh": false,
"disableToolbarTableAutoRefresh": false,
"disableToolbarJournal": false,
"disableToolbarColumnShowHide": false,
"disableToolbarFilterShowHide": false,
"disableToolbarSummaryShowHide": false,
"disableToolbarSearch": false,
"disableToolbarColumnChooser": false,
"disableToolbarClearFilter": false
}
},
{
"collectionTableWidgetSettings": {
"defaultSchemas": ["root.silencing.collections.rules"],
"defaultView": "1",
"defaultFilter": "all"
},
"id": "ZFJvhoDF",
"type": "CollectionTable",
"title": ""
}
],
"layout": {
"lg": [
{
"w": 6,
"h": 5,
"x": 6,
"y": 0,
"i": "E-ItOH43"
},
{
"w": 6,
"h": 5,
"x": 0,
"y": 0,
"i": "ZFJvhoDF"
}
]
},
"breakpoints": {
"lg": 1200,
"md": 996,
"sm": 768,
"xs": 480,
"xxs": 0
},
"cols": {
"lg": 12,
"md": 10,
"sm": 6,
"xs": 4,
"xxs": 2
},
"rowHeight": 150
}
4. Add rules to the collection using the CollectionTable¶
Finally, navigate to the dashboard we just create on the OnSphere front-end. You should see something like this:

Now, go into creation mode in the Collection Table and create a filter by using the filter builder:

Looking at the Alarm Table, you should now see only the alarms that will not match the rule. You can switch the table to a filter with the flag ignoreHideUntil
set as true
to see the hideUntil
value of the alarm that should be equal to the value you set in the rule.

Add this example in your configuration¶
You can directly use the following command to add this example into your configuration:
git checkout origin/example-alarms-silencing-rules .