@oneuptime/common 10.2.18 → 10.2.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Models/DatabaseModels/Index.ts +4 -0
- package/Models/DatabaseModels/ScheduledMaintenanceFeed.ts +2 -0
- package/Models/DatabaseModels/ScheduledMaintenanceLabelRule.ts +742 -0
- package/Models/DatabaseModels/ScheduledMaintenanceOwnerRule.ts +828 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1778703414082-AddScheduledMaintenanceRules.ts +375 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +2 -0
- package/Server/Services/ScheduledMaintenanceLabelRuleEngineService.ts +463 -0
- package/Server/Services/ScheduledMaintenanceLabelRuleService.ts +14 -0
- package/Server/Services/ScheduledMaintenanceOwnerRuleEngineService.ts +545 -0
- package/Server/Services/ScheduledMaintenanceOwnerRuleService.ts +14 -0
- package/Server/Services/ScheduledMaintenanceService.ts +34 -0
- package/Types/Call/CallRequest.ts +29 -5
- package/Types/Docs/DocsLanguage.ts +36 -0
- package/Types/Permission.ts +96 -0
- package/UI/Components/AlertBanner/AlertBanner.tsx +4 -1
- package/UI/Components/Alerts/Alert.tsx +15 -4
- package/UI/Components/Button/DropdownButton.tsx +4 -2
- package/UI/Components/Detail/Detail.tsx +5 -1
- package/UI/Components/Detail/FieldLabel.tsx +14 -6
- package/UI/Components/Detail/PlaceholderText.tsx +4 -1
- package/UI/Components/Dropdown/Dropdown.tsx +13 -4
- package/UI/Components/ErrorMessage/ErrorMessage.tsx +9 -2
- package/UI/Components/Filters/FilterViewer.tsx +42 -31
- package/UI/Components/Filters/FiltersForm.tsx +13 -6
- package/UI/Components/Forms/BasicForm.tsx +23 -6
- package/UI/Components/Forms/Fields/FieldLabel.tsx +18 -6
- package/UI/Components/ModelTable/BaseModelTable.tsx +16 -13
- package/UI/Components/MoreMenu/MoreMenuSection.tsx +4 -1
- package/UI/Components/Navbar/NavBarItem.tsx +4 -1
- package/UI/Components/Navbar/NavBarMenuItem.tsx +7 -2
- package/UI/Components/Navbar/NavBarMenuSubItem.tsx +4 -1
- package/UI/Components/ProgressButtons/ProgressButtonItem.tsx +4 -1
- package/UI/Components/Table/Table.tsx +13 -7
- package/UI/Components/Table/TableHeader.tsx +3 -1
- package/UI/Components/Tabs/Tab.tsx +5 -1
- package/UI/Components/TopAlert/TopAlert.tsx +8 -2
- package/UI/Components/Workflow/ArgumentsForm.tsx +55 -12
- package/UI/Components/Workflow/ComponentSettingsModal.tsx +143 -255
- package/UI/Components/Workflow/ModelFieldPicker.tsx +1234 -0
- package/build/dist/Models/DatabaseModels/Index.js +4 -0
- package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ScheduledMaintenanceFeed.js +2 -0
- package/build/dist/Models/DatabaseModels/ScheduledMaintenanceFeed.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ScheduledMaintenanceLabelRule.js +749 -0
- package/build/dist/Models/DatabaseModels/ScheduledMaintenanceLabelRule.js.map +1 -0
- package/build/dist/Models/DatabaseModels/ScheduledMaintenanceOwnerRule.js +834 -0
- package/build/dist/Models/DatabaseModels/ScheduledMaintenanceOwnerRule.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1778703414082-AddScheduledMaintenanceRules.js +132 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1778703414082-AddScheduledMaintenanceRules.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +2 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Services/ScheduledMaintenanceLabelRuleEngineService.js +375 -0
- package/build/dist/Server/Services/ScheduledMaintenanceLabelRuleEngineService.js.map +1 -0
- package/build/dist/Server/Services/ScheduledMaintenanceLabelRuleService.js +13 -0
- package/build/dist/Server/Services/ScheduledMaintenanceLabelRuleService.js.map +1 -0
- package/build/dist/Server/Services/ScheduledMaintenanceOwnerRuleEngineService.js +431 -0
- package/build/dist/Server/Services/ScheduledMaintenanceOwnerRuleEngineService.js.map +1 -0
- package/build/dist/Server/Services/ScheduledMaintenanceOwnerRuleService.js +13 -0
- package/build/dist/Server/Services/ScheduledMaintenanceOwnerRuleService.js.map +1 -0
- package/build/dist/Server/Services/ScheduledMaintenanceService.js +28 -0
- package/build/dist/Server/Services/ScheduledMaintenanceService.js.map +1 -1
- package/build/dist/Types/Call/CallRequest.js +28 -5
- package/build/dist/Types/Call/CallRequest.js.map +1 -1
- package/build/dist/Types/Docs/DocsLanguage.js +25 -0
- package/build/dist/Types/Docs/DocsLanguage.js.map +1 -0
- package/build/dist/Types/Permission.js +84 -0
- package/build/dist/Types/Permission.js.map +1 -1
- package/build/dist/UI/Components/AlertBanner/AlertBanner.js +5 -1
- package/build/dist/UI/Components/AlertBanner/AlertBanner.js.map +1 -1
- package/build/dist/UI/Components/Alerts/Alert.js +9 -4
- package/build/dist/UI/Components/Alerts/Alert.js.map +1 -1
- package/build/dist/UI/Components/Button/DropdownButton.js +6 -2
- package/build/dist/UI/Components/Button/DropdownButton.js.map +1 -1
- package/build/dist/UI/Components/Detail/Detail.js +4 -1
- package/build/dist/UI/Components/Detail/Detail.js.map +1 -1
- package/build/dist/UI/Components/Detail/FieldLabel.js +11 -6
- package/build/dist/UI/Components/Detail/FieldLabel.js.map +1 -1
- package/build/dist/UI/Components/Detail/PlaceholderText.js +5 -1
- package/build/dist/UI/Components/Detail/PlaceholderText.js.map +1 -1
- package/build/dist/UI/Components/Dropdown/Dropdown.js +11 -4
- package/build/dist/UI/Components/Dropdown/Dropdown.js.map +1 -1
- package/build/dist/UI/Components/ErrorMessage/ErrorMessage.js +8 -2
- package/build/dist/UI/Components/ErrorMessage/ErrorMessage.js.map +1 -1
- package/build/dist/UI/Components/Filters/FilterViewer.js +49 -32
- package/build/dist/UI/Components/Filters/FilterViewer.js.map +1 -1
- package/build/dist/UI/Components/Filters/FiltersForm.js +9 -3
- package/build/dist/UI/Components/Filters/FiltersForm.js.map +1 -1
- package/build/dist/UI/Components/Forms/BasicForm.js +16 -6
- package/build/dist/UI/Components/Forms/BasicForm.js.map +1 -1
- package/build/dist/UI/Components/Forms/Fields/FieldLabel.js +13 -6
- package/build/dist/UI/Components/Forms/Fields/FieldLabel.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js +15 -10
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
- package/build/dist/UI/Components/MoreMenu/MoreMenuSection.js +5 -1
- package/build/dist/UI/Components/MoreMenu/MoreMenuSection.js.map +1 -1
- package/build/dist/UI/Components/Navbar/NavBarItem.js +5 -1
- package/build/dist/UI/Components/Navbar/NavBarItem.js.map +1 -1
- package/build/dist/UI/Components/Navbar/NavBarMenuItem.js +7 -2
- package/build/dist/UI/Components/Navbar/NavBarMenuItem.js.map +1 -1
- package/build/dist/UI/Components/Navbar/NavBarMenuSubItem.js +5 -1
- package/build/dist/UI/Components/Navbar/NavBarMenuSubItem.js.map +1 -1
- package/build/dist/UI/Components/ProgressButtons/ProgressButtonItem.js +5 -1
- package/build/dist/UI/Components/ProgressButtons/ProgressButtonItem.js.map +1 -1
- package/build/dist/UI/Components/Table/Table.js +12 -7
- package/build/dist/UI/Components/Table/Table.js.map +1 -1
- package/build/dist/UI/Components/Table/TableHeader.js +4 -2
- package/build/dist/UI/Components/Table/TableHeader.js.map +1 -1
- package/build/dist/UI/Components/Tabs/Tab.js +5 -1
- package/build/dist/UI/Components/Tabs/Tab.js.map +1 -1
- package/build/dist/UI/Components/TopAlert/TopAlert.js +7 -2
- package/build/dist/UI/Components/TopAlert/TopAlert.js.map +1 -1
- package/build/dist/UI/Components/Workflow/ArgumentsForm.js +32 -10
- package/build/dist/UI/Components/Workflow/ArgumentsForm.js.map +1 -1
- package/build/dist/UI/Components/Workflow/ComponentSettingsModal.js +57 -145
- package/build/dist/UI/Components/Workflow/ComponentSettingsModal.js.map +1 -1
- package/build/dist/UI/Components/Workflow/ModelFieldPicker.js +694 -0
- package/build/dist/UI/Components/Workflow/ModelFieldPicker.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,463 @@
|
|
|
1
|
+
import Label from "../../Models/DatabaseModels/Label";
|
|
2
|
+
import Monitor from "../../Models/DatabaseModels/Monitor";
|
|
3
|
+
import ScheduledMaintenance from "../../Models/DatabaseModels/ScheduledMaintenance";
|
|
4
|
+
import ScheduledMaintenanceLabelRule from "../../Models/DatabaseModels/ScheduledMaintenanceLabelRule";
|
|
5
|
+
import LabelService from "./LabelService";
|
|
6
|
+
import MonitorService from "./MonitorService";
|
|
7
|
+
import ScheduledMaintenanceFeedService from "./ScheduledMaintenanceFeedService";
|
|
8
|
+
import ScheduledMaintenanceLabelRuleService from "./ScheduledMaintenanceLabelRuleService";
|
|
9
|
+
import ScheduledMaintenanceService from "./ScheduledMaintenanceService";
|
|
10
|
+
import { ScheduledMaintenanceFeedEventType } from "../../Models/DatabaseModels/ScheduledMaintenanceFeed";
|
|
11
|
+
import { Indigo500 } from "../../Types/BrandColors";
|
|
12
|
+
import ObjectID from "../../Types/ObjectID";
|
|
13
|
+
import LIMIT_MAX from "../../Types/Database/LimitMax";
|
|
14
|
+
import QueryHelper from "../Types/Database/QueryHelper";
|
|
15
|
+
import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
|
|
16
|
+
import logger, { LogAttributes } from "../Utils/Logger";
|
|
17
|
+
|
|
18
|
+
class ScheduledMaintenanceLabelRuleEngineServiceClass {
|
|
19
|
+
/**
|
|
20
|
+
* Evaluates ScheduledMaintenanceLabelRule rows for the given event and
|
|
21
|
+
* attaches matched labels to the event. Each matched rule contributes:
|
|
22
|
+
* - labels listed on `labelsToAdd`
|
|
23
|
+
* - all labels of the event's monitors when `inheritLabelsFromMonitors`
|
|
24
|
+
* The union is deduped against labels already on the event before insert
|
|
25
|
+
* to avoid PK conflicts on the ScheduledMaintenanceLabel join table.
|
|
26
|
+
*/
|
|
27
|
+
@CaptureSpan()
|
|
28
|
+
public async applyRulesToScheduledMaintenance(
|
|
29
|
+
scheduledMaintenance: ScheduledMaintenance,
|
|
30
|
+
): Promise<void> {
|
|
31
|
+
if (!scheduledMaintenance.id || !scheduledMaintenance.projectId) {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
try {
|
|
36
|
+
const rules: Array<ScheduledMaintenanceLabelRule> =
|
|
37
|
+
await ScheduledMaintenanceLabelRuleService.findBy({
|
|
38
|
+
query: {
|
|
39
|
+
projectId: scheduledMaintenance.projectId,
|
|
40
|
+
isEnabled: true,
|
|
41
|
+
},
|
|
42
|
+
props: { isRoot: true },
|
|
43
|
+
select: {
|
|
44
|
+
_id: true,
|
|
45
|
+
name: true,
|
|
46
|
+
monitors: { _id: true },
|
|
47
|
+
scheduledMaintenanceLabels: { _id: true },
|
|
48
|
+
monitorLabels: { _id: true },
|
|
49
|
+
titlePattern: true,
|
|
50
|
+
descriptionPattern: true,
|
|
51
|
+
monitorNamePattern: true,
|
|
52
|
+
monitorDescriptionPattern: true,
|
|
53
|
+
labelsToAdd: { _id: true },
|
|
54
|
+
inheritLabelsFromMonitors: true,
|
|
55
|
+
},
|
|
56
|
+
limit: 100,
|
|
57
|
+
skip: 0,
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
if (rules.length === 0) {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const labelIdsToAdd: Set<string> = new Set();
|
|
65
|
+
let inheritFromMonitors: boolean = false;
|
|
66
|
+
const matchedRules: Array<ScheduledMaintenanceLabelRule> = [];
|
|
67
|
+
|
|
68
|
+
for (const rule of rules) {
|
|
69
|
+
const matches: boolean = await this.doesScheduledMaintenanceMatchRule(
|
|
70
|
+
scheduledMaintenance,
|
|
71
|
+
rule,
|
|
72
|
+
);
|
|
73
|
+
if (!matches) {
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
matchedRules.push(rule);
|
|
77
|
+
for (const label of rule.labelsToAdd || []) {
|
|
78
|
+
if (label.id) {
|
|
79
|
+
labelIdsToAdd.add(label.id.toString());
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
if (rule.inheritLabelsFromMonitors) {
|
|
83
|
+
inheritFromMonitors = true;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (inheritFromMonitors && scheduledMaintenance.monitors?.length) {
|
|
88
|
+
for (const eventMonitor of scheduledMaintenance.monitors) {
|
|
89
|
+
if (!eventMonitor.id) {
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
const monitor: Monitor | null = await MonitorService.findOneById({
|
|
93
|
+
id: eventMonitor.id,
|
|
94
|
+
select: { labels: { _id: true } },
|
|
95
|
+
props: { isRoot: true },
|
|
96
|
+
});
|
|
97
|
+
for (const label of monitor?.labels || []) {
|
|
98
|
+
if (label.id) {
|
|
99
|
+
labelIdsToAdd.add(label.id.toString());
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (labelIdsToAdd.size === 0) {
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const eventWithLabels: ScheduledMaintenance | null =
|
|
110
|
+
await ScheduledMaintenanceService.findOneById({
|
|
111
|
+
id: scheduledMaintenance.id,
|
|
112
|
+
select: { labels: { _id: true } },
|
|
113
|
+
props: { isRoot: true },
|
|
114
|
+
});
|
|
115
|
+
const existingLabelIds: Set<string> = new Set(
|
|
116
|
+
(eventWithLabels?.labels || [])
|
|
117
|
+
.map((l: Label) => {
|
|
118
|
+
return l.id?.toString() || "";
|
|
119
|
+
})
|
|
120
|
+
.filter((id: string) => {
|
|
121
|
+
return id !== "";
|
|
122
|
+
}),
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
const newLabelIds: Array<string> = Array.from(labelIdsToAdd).filter(
|
|
126
|
+
(id: string) => {
|
|
127
|
+
return !existingLabelIds.has(id);
|
|
128
|
+
},
|
|
129
|
+
);
|
|
130
|
+
if (newLabelIds.length === 0) {
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
await ScheduledMaintenanceService.getRepository()
|
|
135
|
+
.createQueryBuilder()
|
|
136
|
+
.relation(ScheduledMaintenance, "labels")
|
|
137
|
+
.of(scheduledMaintenance.id.toString())
|
|
138
|
+
.add(newLabelIds);
|
|
139
|
+
|
|
140
|
+
/*
|
|
141
|
+
* Sync in-memory event.labels with the now-persisted set so any
|
|
142
|
+
* downstream consumers in the same onCreateSuccess chain see the new
|
|
143
|
+
* labels.
|
|
144
|
+
*/
|
|
145
|
+
const mergedLabelIds: Set<string> = new Set([
|
|
146
|
+
...existingLabelIds,
|
|
147
|
+
...newLabelIds,
|
|
148
|
+
]);
|
|
149
|
+
scheduledMaintenance.labels = Array.from(mergedLabelIds).map(
|
|
150
|
+
(id: string) => {
|
|
151
|
+
const label: Label = new Label();
|
|
152
|
+
label.id = new ObjectID(id);
|
|
153
|
+
return label;
|
|
154
|
+
},
|
|
155
|
+
);
|
|
156
|
+
|
|
157
|
+
logger.debug(
|
|
158
|
+
`ScheduledMaintenanceLabelRuleEngine attached ${newLabelIds.length} labels to event ${scheduledMaintenance.id}`,
|
|
159
|
+
{
|
|
160
|
+
projectId: scheduledMaintenance.projectId.toString(),
|
|
161
|
+
} as LogAttributes,
|
|
162
|
+
);
|
|
163
|
+
|
|
164
|
+
await this.createRuleExecutedFeedItem({
|
|
165
|
+
scheduledMaintenance,
|
|
166
|
+
matchedRules,
|
|
167
|
+
addedLabelIds: newLabelIds,
|
|
168
|
+
});
|
|
169
|
+
} catch (error) {
|
|
170
|
+
logger.error(
|
|
171
|
+
`Error applying scheduled maintenance label rules: ${error}`,
|
|
172
|
+
{
|
|
173
|
+
projectId: scheduledMaintenance.projectId?.toString(),
|
|
174
|
+
scheduledMaintenanceId: scheduledMaintenance.id?.toString(),
|
|
175
|
+
} as LogAttributes,
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
@CaptureSpan()
|
|
181
|
+
private async createRuleExecutedFeedItem(data: {
|
|
182
|
+
scheduledMaintenance: ScheduledMaintenance;
|
|
183
|
+
matchedRules: Array<ScheduledMaintenanceLabelRule>;
|
|
184
|
+
addedLabelIds: Array<string>;
|
|
185
|
+
}): Promise<void> {
|
|
186
|
+
const { scheduledMaintenance, matchedRules, addedLabelIds } = data;
|
|
187
|
+
if (
|
|
188
|
+
!scheduledMaintenance.id ||
|
|
189
|
+
!scheduledMaintenance.projectId ||
|
|
190
|
+
matchedRules.length === 0 ||
|
|
191
|
+
addedLabelIds.length === 0
|
|
192
|
+
) {
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
try {
|
|
197
|
+
const labelObjectIds: Array<ObjectID> = addedLabelIds.map(
|
|
198
|
+
(id: string) => {
|
|
199
|
+
return new ObjectID(id);
|
|
200
|
+
},
|
|
201
|
+
);
|
|
202
|
+
|
|
203
|
+
const labels: Array<Label> = await LabelService.findBy({
|
|
204
|
+
query: {
|
|
205
|
+
_id: QueryHelper.any(labelObjectIds),
|
|
206
|
+
},
|
|
207
|
+
select: { name: true },
|
|
208
|
+
props: { isRoot: true },
|
|
209
|
+
limit: LIMIT_MAX,
|
|
210
|
+
skip: 0,
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
const labelNames: Array<string> = labels
|
|
214
|
+
.map((l: Label) => {
|
|
215
|
+
return l.name?.toString() || "";
|
|
216
|
+
})
|
|
217
|
+
.filter((n: string) => {
|
|
218
|
+
return n !== "";
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
const ruleNames: Array<string> = matchedRules
|
|
222
|
+
.map((r: ScheduledMaintenanceLabelRule) => {
|
|
223
|
+
return r.name?.toString() || "Unnamed Rule";
|
|
224
|
+
})
|
|
225
|
+
.filter((n: string) => {
|
|
226
|
+
return n !== "";
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
const rulesPart: string =
|
|
230
|
+
ruleNames.length === 1
|
|
231
|
+
? `**${ruleNames[0]}**`
|
|
232
|
+
: ruleNames
|
|
233
|
+
.map((n: string) => {
|
|
234
|
+
return `**${n}**`;
|
|
235
|
+
})
|
|
236
|
+
.join(", ");
|
|
237
|
+
|
|
238
|
+
const labelsPart: string =
|
|
239
|
+
labelNames.length > 0
|
|
240
|
+
? labelNames
|
|
241
|
+
.map((n: string) => {
|
|
242
|
+
return `\n- ${n}`;
|
|
243
|
+
})
|
|
244
|
+
.join("")
|
|
245
|
+
: "\n- (no named labels)";
|
|
246
|
+
|
|
247
|
+
const feedInfoInMarkdown: string = `🏷️ **Scheduled Maintenance Label Rule${
|
|
248
|
+
matchedRules.length > 1 ? "s" : ""
|
|
249
|
+
} executed:** ${rulesPart}\n\nAdded the following label${
|
|
250
|
+
labelNames.length === 1 ? "" : "s"
|
|
251
|
+
} to the event:${labelsPart}`;
|
|
252
|
+
|
|
253
|
+
await ScheduledMaintenanceFeedService.createScheduledMaintenanceFeedItem({
|
|
254
|
+
scheduledMaintenanceId: scheduledMaintenance.id,
|
|
255
|
+
projectId: scheduledMaintenance.projectId,
|
|
256
|
+
scheduledMaintenanceFeedEventType:
|
|
257
|
+
ScheduledMaintenanceFeedEventType.LabelRuleExecuted,
|
|
258
|
+
displayColor: Indigo500,
|
|
259
|
+
feedInfoInMarkdown,
|
|
260
|
+
});
|
|
261
|
+
} catch (error) {
|
|
262
|
+
logger.error(
|
|
263
|
+
`ScheduledMaintenanceLabelRuleEngine: failed to create rule-executed feed item: ${
|
|
264
|
+
error instanceof Error ? error.message : String(error)
|
|
265
|
+
}`,
|
|
266
|
+
{
|
|
267
|
+
projectId: scheduledMaintenance.projectId?.toString(),
|
|
268
|
+
scheduledMaintenanceId: scheduledMaintenance.id?.toString(),
|
|
269
|
+
} as LogAttributes,
|
|
270
|
+
);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
@CaptureSpan()
|
|
275
|
+
private async doesScheduledMaintenanceMatchRule(
|
|
276
|
+
scheduledMaintenance: ScheduledMaintenance,
|
|
277
|
+
rule: ScheduledMaintenanceLabelRule,
|
|
278
|
+
): Promise<boolean> {
|
|
279
|
+
if (rule.monitors && rule.monitors.length > 0) {
|
|
280
|
+
if (
|
|
281
|
+
!scheduledMaintenance.monitors ||
|
|
282
|
+
scheduledMaintenance.monitors.length === 0
|
|
283
|
+
) {
|
|
284
|
+
return false;
|
|
285
|
+
}
|
|
286
|
+
const ruleMonitorIds: Array<string> = rule.monitors.map((m: Monitor) => {
|
|
287
|
+
return m.id?.toString() || "";
|
|
288
|
+
});
|
|
289
|
+
const eventMonitorIds: Array<string> = scheduledMaintenance.monitors.map(
|
|
290
|
+
(m: Monitor) => {
|
|
291
|
+
return m.id?.toString() || "";
|
|
292
|
+
},
|
|
293
|
+
);
|
|
294
|
+
if (
|
|
295
|
+
!ruleMonitorIds.some((id: string) => {
|
|
296
|
+
return eventMonitorIds.includes(id);
|
|
297
|
+
})
|
|
298
|
+
) {
|
|
299
|
+
return false;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
if (
|
|
304
|
+
rule.scheduledMaintenanceLabels &&
|
|
305
|
+
rule.scheduledMaintenanceLabels.length > 0
|
|
306
|
+
) {
|
|
307
|
+
if (
|
|
308
|
+
!scheduledMaintenance.labels ||
|
|
309
|
+
scheduledMaintenance.labels.length === 0
|
|
310
|
+
) {
|
|
311
|
+
return false;
|
|
312
|
+
}
|
|
313
|
+
const ruleLabelIds: Array<string> = rule.scheduledMaintenanceLabels.map(
|
|
314
|
+
(l: Label) => {
|
|
315
|
+
return l.id?.toString() || "";
|
|
316
|
+
},
|
|
317
|
+
);
|
|
318
|
+
const eventLabelIds: Array<string> = scheduledMaintenance.labels.map(
|
|
319
|
+
(l: Label) => {
|
|
320
|
+
return l.id?.toString() || "";
|
|
321
|
+
},
|
|
322
|
+
);
|
|
323
|
+
if (
|
|
324
|
+
!ruleLabelIds.some((id: string) => {
|
|
325
|
+
return eventLabelIds.includes(id);
|
|
326
|
+
})
|
|
327
|
+
) {
|
|
328
|
+
return false;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
const hasMonitorCriteria: boolean = Boolean(
|
|
333
|
+
(rule.monitorLabels && rule.monitorLabels.length > 0) ||
|
|
334
|
+
rule.monitorNamePattern ||
|
|
335
|
+
rule.monitorDescriptionPattern,
|
|
336
|
+
);
|
|
337
|
+
|
|
338
|
+
if (hasMonitorCriteria) {
|
|
339
|
+
if (
|
|
340
|
+
!scheduledMaintenance.monitors ||
|
|
341
|
+
scheduledMaintenance.monitors.length === 0
|
|
342
|
+
) {
|
|
343
|
+
return false;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
let anyMonitorMatches: boolean = false;
|
|
347
|
+
for (const eventMonitor of scheduledMaintenance.monitors) {
|
|
348
|
+
if (!eventMonitor.id) {
|
|
349
|
+
continue;
|
|
350
|
+
}
|
|
351
|
+
const monitor: Monitor | null = await MonitorService.findOneById({
|
|
352
|
+
id: eventMonitor.id,
|
|
353
|
+
select: {
|
|
354
|
+
name: true,
|
|
355
|
+
description: true,
|
|
356
|
+
labels: { _id: true },
|
|
357
|
+
},
|
|
358
|
+
props: { isRoot: true },
|
|
359
|
+
});
|
|
360
|
+
if (!monitor) {
|
|
361
|
+
continue;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
let monitorMatches: boolean = true;
|
|
365
|
+
|
|
366
|
+
if (rule.monitorLabels && rule.monitorLabels.length > 0) {
|
|
367
|
+
if (!monitor.labels || monitor.labels.length === 0) {
|
|
368
|
+
monitorMatches = false;
|
|
369
|
+
} else {
|
|
370
|
+
const ruleMonitorLabelIds: Array<string> = rule.monitorLabels.map(
|
|
371
|
+
(l: Label) => {
|
|
372
|
+
return l.id?.toString() || "";
|
|
373
|
+
},
|
|
374
|
+
);
|
|
375
|
+
const monitorLabelIds: Array<string> = monitor.labels.map(
|
|
376
|
+
(l: Label) => {
|
|
377
|
+
return l.id?.toString() || "";
|
|
378
|
+
},
|
|
379
|
+
);
|
|
380
|
+
if (
|
|
381
|
+
!ruleMonitorLabelIds.some((id: string) => {
|
|
382
|
+
return monitorLabelIds.includes(id);
|
|
383
|
+
})
|
|
384
|
+
) {
|
|
385
|
+
monitorMatches = false;
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
if (
|
|
391
|
+
monitorMatches &&
|
|
392
|
+
rule.monitorNamePattern &&
|
|
393
|
+
(!monitor.name ||
|
|
394
|
+
!this.testRegex(rule.monitorNamePattern, monitor.name, rule))
|
|
395
|
+
) {
|
|
396
|
+
monitorMatches = false;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
if (
|
|
400
|
+
monitorMatches &&
|
|
401
|
+
rule.monitorDescriptionPattern &&
|
|
402
|
+
(!monitor.description ||
|
|
403
|
+
!this.testRegex(
|
|
404
|
+
rule.monitorDescriptionPattern,
|
|
405
|
+
monitor.description,
|
|
406
|
+
rule,
|
|
407
|
+
))
|
|
408
|
+
) {
|
|
409
|
+
monitorMatches = false;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
if (monitorMatches) {
|
|
413
|
+
anyMonitorMatches = true;
|
|
414
|
+
break;
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
if (!anyMonitorMatches) {
|
|
419
|
+
return false;
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
if (
|
|
424
|
+
rule.titlePattern &&
|
|
425
|
+
(!scheduledMaintenance.title ||
|
|
426
|
+
!this.testRegex(rule.titlePattern, scheduledMaintenance.title, rule))
|
|
427
|
+
) {
|
|
428
|
+
return false;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
if (
|
|
432
|
+
rule.descriptionPattern &&
|
|
433
|
+
(!scheduledMaintenance.description ||
|
|
434
|
+
!this.testRegex(
|
|
435
|
+
rule.descriptionPattern,
|
|
436
|
+
scheduledMaintenance.description,
|
|
437
|
+
rule,
|
|
438
|
+
))
|
|
439
|
+
) {
|
|
440
|
+
return false;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
return true;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
private testRegex(
|
|
447
|
+
pattern: string,
|
|
448
|
+
value: string,
|
|
449
|
+
rule: ScheduledMaintenanceLabelRule,
|
|
450
|
+
): boolean {
|
|
451
|
+
try {
|
|
452
|
+
const regex: RegExp = new RegExp(pattern, "i");
|
|
453
|
+
return regex.test(value);
|
|
454
|
+
} catch {
|
|
455
|
+
logger.warn(
|
|
456
|
+
`Invalid regex in scheduled maintenance label rule ${rule.id}: ${pattern}`,
|
|
457
|
+
);
|
|
458
|
+
return false;
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
export default new ScheduledMaintenanceLabelRuleEngineServiceClass();
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import DatabaseService from "./DatabaseService";
|
|
2
|
+
import Model from "../../Models/DatabaseModels/ScheduledMaintenanceLabelRule";
|
|
3
|
+
import { IsBillingEnabled } from "../EnvironmentConfig";
|
|
4
|
+
|
|
5
|
+
export class Service extends DatabaseService<Model> {
|
|
6
|
+
public constructor() {
|
|
7
|
+
super(Model);
|
|
8
|
+
if (IsBillingEnabled) {
|
|
9
|
+
this.hardDeleteItemsOlderThanInDays("createdAt", 3 * 365);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export default new Service();
|