Skip to content

Commit ded6ea5

Browse files
authored
Merge pull request #1945 from elementary-data/ele-4677-add-exclude-option-to-edr-monitor
added excludes option to edr monitor
2 parents 788ea52 + 152b5b6 commit ded6ea5

File tree

3 files changed

+117
-36
lines changed

3 files changed

+117
-36
lines changed

elementary/monitor/cli.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,15 @@ def get_cli_properties() -> dict:
269269
help="Filter the alerts by tags:<tags separated by commas> / owners:<owners separated by commas> / models:<models separated by commas> / "
270270
"statuses:<warn/fail/error/skipped> / resource_types:<model/test>.",
271271
)
272+
@click.option(
273+
"--excludes",
274+
"-ex",
275+
type=str,
276+
default=None,
277+
multiple=True,
278+
help="Exclude alerts by tags:<tags separated by commas> / owners:<owners separated by commas> / models:<models separated by commas> / "
279+
"statuses:<warn/fail/error/skipped> / resource_types:<model/test>.",
280+
)
272281
@click.option(
273282
"--teams-webhook",
274283
"-tw",
@@ -305,6 +314,7 @@ def monitor(
305314
override_dbt_project_config,
306315
report_url,
307316
filters,
317+
excludes,
308318
teams_webhook,
309319
):
310320
"""
@@ -344,8 +354,8 @@ def monitor(
344354
config.validate_monitor()
345355

346356
alert_filters = FiltersSchema()
347-
if bool(filters):
348-
alert_filters = FiltersSchema.from_cli_params(filters)
357+
if bool(filters) or bool(excludes):
358+
alert_filters = FiltersSchema.from_cli_params(filters, excludes)
349359
elif select is not None:
350360
click.secho(
351361
'\n"--select" is deprecated and won\'t be supported in the near future.\n'

elementary/monitor/data_monitoring/schema.py

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -178,8 +178,16 @@ def validate_report_selector(self) -> None:
178178
)
179179

180180
@staticmethod
181-
def from_cli_params(cli_filters: Tuple[str]) -> "FiltersSchema":
182-
if not cli_filters:
181+
def from_cli_params(
182+
cli_filters: Tuple[str], cli_excludes: Tuple[str]
183+
) -> "FiltersSchema":
184+
all_filters: list[tuple[str, FilterType]] = []
185+
for cli_filter in cli_filters:
186+
all_filters.append((cli_filter, FilterType.IS))
187+
for cli_exclude in cli_excludes:
188+
all_filters.append((cli_exclude, FilterType.IS_NOT))
189+
190+
if not all_filters:
183191
return FiltersSchema()
184192

185193
tags = []
@@ -188,26 +196,26 @@ def from_cli_params(cli_filters: Tuple[str]) -> "FiltersSchema":
188196
statuses = []
189197
resource_types = []
190198

191-
for cli_filter in cli_filters:
199+
for cli_filter, filter_type in all_filters:
192200
tags_match = FiltersSchema._match_filter_regex(
193201
filter_string=cli_filter, regex=re.compile(r"tags:(.*)")
194202
)
195203
if tags_match:
196-
tags.append(FilterSchema(values=tags_match))
204+
tags.append(FilterSchema(values=tags_match, type=filter_type))
197205
continue
198206

199207
owners_match = FiltersSchema._match_filter_regex(
200208
filter_string=cli_filter, regex=re.compile(r"owners:(.*)")
201209
)
202210
if owners_match:
203-
owners.append(FilterSchema(values=owners_match))
211+
owners.append(FilterSchema(values=owners_match, type=filter_type))
204212
continue
205213

206214
models_match = FiltersSchema._match_filter_regex(
207215
filter_string=cli_filter, regex=re.compile(r"models:(.*)")
208216
)
209217
if models_match:
210-
models.append(FilterSchema(values=models_match))
218+
models.append(FilterSchema(values=models_match, type=filter_type))
211219
continue
212220

213221
statuses_match = FiltersSchema._match_filter_regex(
@@ -216,7 +224,8 @@ def from_cli_params(cli_filters: Tuple[str]) -> "FiltersSchema":
216224
if statuses_match:
217225
statuses.append(
218226
StatusFilterSchema(
219-
values=[Status(status) for status in statuses_match]
227+
values=[Status(status) for status in statuses_match],
228+
type=filter_type,
220229
)
221230
)
222231
continue
@@ -230,7 +239,8 @@ def from_cli_params(cli_filters: Tuple[str]) -> "FiltersSchema":
230239
values=[
231240
ResourceType(resource_type)
232241
for resource_type in resource_types_match
233-
]
242+
],
243+
type=filter_type,
234244
)
235245
)
236246
continue
@@ -239,11 +249,14 @@ def from_cli_params(cli_filters: Tuple[str]) -> "FiltersSchema":
239249
f'Filter "{cli_filter.split(":")[0]}" is not supported - Skipping this filter ("{cli_filter}").'
240250
)
241251

252+
if not any(status_filter.type == FilterType.IS for status_filter in statuses):
253+
statuses.extend(_get_default_statuses_filter())
254+
242255
return FiltersSchema(
243256
tags=tags,
244257
owners=owners,
245258
models=models,
246-
statuses=statuses if statuses else _get_default_statuses_filter(),
259+
statuses=statuses,
247260
resource_types=resource_types,
248261
)
249262

tests/unit/monitor/data_monitoring/test_filters_schema.py

Lines changed: 83 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import pytest
22

3-
from elementary.monitor.data_monitoring.schema import FiltersSchema
3+
from elementary.monitor.data_monitoring.schema import FiltersSchema, FilterType
44

55

66
def test_empty_from_cli_params():
77
cli_filter = ()
8-
filter_schema = FiltersSchema.from_cli_params(cli_filter)
8+
cli_excludes = ()
9+
filter_schema = FiltersSchema.from_cli_params(cli_filter, cli_excludes)
910
assert len(filter_schema.tags) == 0
1011
assert len(filter_schema.owners) == 0
1112
assert len(filter_schema.models) == 0
@@ -18,7 +19,8 @@ def test_empty_from_cli_params():
1819

1920
def test_tags_key_from_cli_params():
2021
cli_filter = ("tags:tag1",)
21-
filter_schema = FiltersSchema.from_cli_params(cli_filter)
22+
cli_excludes = ()
23+
filter_schema = FiltersSchema.from_cli_params(cli_filter, cli_excludes)
2224
assert len(filter_schema.tags) == 1
2325
assert filter_schema.tags[0].values == ["tag1"]
2426
assert len(filter_schema.owners) == 0
@@ -30,7 +32,8 @@ def test_tags_key_from_cli_params():
3032
assert len(filter_schema.resource_types) == 0
3133

3234
cli_filter = ("tags:tag1,tag2",)
33-
filter_schema = FiltersSchema.from_cli_params(cli_filter)
35+
cli_excludes = ()
36+
filter_schema = FiltersSchema.from_cli_params(cli_filter, cli_excludes)
3437
assert len(filter_schema.tags) == 1
3538
assert sorted(filter_schema.tags[0].values) == sorted(["tag1", "tag2"])
3639
assert len(filter_schema.owners) == 0
@@ -42,7 +45,8 @@ def test_tags_key_from_cli_params():
4245
assert len(filter_schema.resource_types) == 0
4346

4447
cli_filter = ("tags:tag1", "tags:tag2")
45-
filter_schema = FiltersSchema.from_cli_params(cli_filter)
48+
cli_excludes = ()
49+
filter_schema = FiltersSchema.from_cli_params(cli_filter, cli_excludes)
4650
assert len(filter_schema.tags) == 2
4751
assert filter_schema.tags[0].values == ["tag1"]
4852
assert filter_schema.tags[1].values == ["tag2"]
@@ -57,7 +61,8 @@ def test_tags_key_from_cli_params():
5761

5862
def test_owners_key_from_cli_params():
5963
cli_filter = ("owners:freddy",)
60-
filter_schema = FiltersSchema.from_cli_params(cli_filter)
64+
cli_excludes = ()
65+
filter_schema = FiltersSchema.from_cli_params(cli_filter, cli_excludes)
6166
assert len(filter_schema.tags) == 0
6267
assert len(filter_schema.owners) == 1
6368
assert filter_schema.owners[0].values == ["freddy"]
@@ -69,7 +74,8 @@ def test_owners_key_from_cli_params():
6974
assert len(filter_schema.resource_types) == 0
7075

7176
cli_filter = ("owners:freddy,dredd",)
72-
filter_schema = FiltersSchema.from_cli_params(cli_filter)
77+
cli_excludes = ()
78+
filter_schema = FiltersSchema.from_cli_params(cli_filter, cli_excludes)
7379
assert len(filter_schema.tags) == 0
7480
assert len(filter_schema.owners) == 1
7581
assert sorted(filter_schema.owners[0].values) == sorted(["freddy", "dredd"])
@@ -81,7 +87,8 @@ def test_owners_key_from_cli_params():
8187
assert len(filter_schema.resource_types) == 0
8288

8389
cli_filter = ("owners:freddy", "owners:dredd")
84-
filter_schema = FiltersSchema.from_cli_params(cli_filter)
90+
cli_excludes = ()
91+
filter_schema = FiltersSchema.from_cli_params(cli_filter, cli_excludes)
8592
assert len(filter_schema.tags) == 0
8693
assert len(filter_schema.owners) == 2
8794
assert filter_schema.owners[0].values == ["freddy"]
@@ -96,7 +103,8 @@ def test_owners_key_from_cli_params():
96103

97104
def test_models_key_from_cli_params():
98105
cli_filter = ("models:freddy",)
99-
filter_schema = FiltersSchema.from_cli_params(cli_filter)
106+
cli_excludes = ()
107+
filter_schema = FiltersSchema.from_cli_params(cli_filter, cli_excludes)
100108
assert len(filter_schema.tags) == 0
101109
assert len(filter_schema.models) == 1
102110
assert filter_schema.models[0].values == ["freddy"]
@@ -108,7 +116,8 @@ def test_models_key_from_cli_params():
108116
assert len(filter_schema.resource_types) == 0
109117

110118
cli_filter = ("models:freddy,dredd",)
111-
filter_schema = FiltersSchema.from_cli_params(cli_filter)
119+
cli_excludes = ()
120+
filter_schema = FiltersSchema.from_cli_params(cli_filter, cli_excludes)
112121
assert len(filter_schema.tags) == 0
113122
assert len(filter_schema.models) == 1
114123
assert sorted(filter_schema.models[0].values) == sorted(["freddy", "dredd"])
@@ -120,7 +129,8 @@ def test_models_key_from_cli_params():
120129
assert len(filter_schema.resource_types) == 0
121130

122131
cli_filter = ("models:freddy", "models:dredd")
123-
filter_schema = FiltersSchema.from_cli_params(cli_filter)
132+
cli_excludes = ()
133+
filter_schema = FiltersSchema.from_cli_params(cli_filter, cli_excludes)
124134
assert len(filter_schema.tags) == 0
125135
assert len(filter_schema.models) == 2
126136
assert filter_schema.models[0].values == ["freddy"]
@@ -136,18 +146,22 @@ def test_models_key_from_cli_params():
136146
def test_statuses_key_from_cli_params():
137147
with pytest.raises(ValueError):
138148
cli_filter = ("statuses:freddy",)
139-
FiltersSchema.from_cli_params(cli_filter)
149+
cli_excludes = ()
150+
FiltersSchema.from_cli_params(cli_filter, cli_excludes)
140151

141152
with pytest.raises(ValueError):
142153
cli_filter = ("statuses:warn,freddy",)
143-
FiltersSchema.from_cli_params(cli_filter)
154+
cli_excludes = ()
155+
FiltersSchema.from_cli_params(cli_filter, cli_excludes)
144156

145157
with pytest.raises(ValueError):
146158
cli_filter = ("statuses:warn", "statuses:freddy")
147-
FiltersSchema.from_cli_params(cli_filter)
159+
cli_excludes = ()
160+
FiltersSchema.from_cli_params(cli_filter, cli_excludes)
148161

149162
cli_filter = ("statuses:warn",)
150-
filter_schema = FiltersSchema.from_cli_params(cli_filter)
163+
cli_excludes = ()
164+
filter_schema = FiltersSchema.from_cli_params(cli_filter, cli_excludes)
151165
assert len(filter_schema.tags) == 0
152166
assert len(filter_schema.models) == 0
153167
assert len(filter_schema.owners) == 0
@@ -156,7 +170,8 @@ def test_statuses_key_from_cli_params():
156170
assert len(filter_schema.resource_types) == 0
157171

158172
cli_filter = ("statuses:warn,fail",)
159-
filter_schema = FiltersSchema.from_cli_params(cli_filter)
173+
cli_excludes = ()
174+
filter_schema = FiltersSchema.from_cli_params(cli_filter, cli_excludes)
160175
assert len(filter_schema.tags) == 0
161176
assert len(filter_schema.models) == 0
162177
assert len(filter_schema.owners) == 0
@@ -165,7 +180,8 @@ def test_statuses_key_from_cli_params():
165180
assert len(filter_schema.resource_types) == 0
166181

167182
cli_filter = ("statuses:warn", "statuses:fail")
168-
filter_schema = FiltersSchema.from_cli_params(cli_filter)
183+
cli_excludes = ()
184+
filter_schema = FiltersSchema.from_cli_params(cli_filter, cli_excludes)
169185
assert len(filter_schema.tags) == 0
170186
assert len(filter_schema.models) == 0
171187
assert len(filter_schema.owners) == 0
@@ -178,18 +194,22 @@ def test_statuses_key_from_cli_params():
178194
def test_resource_types_key_from_cli_params():
179195
with pytest.raises(ValueError):
180196
cli_filter = ("resource_types:freddy",)
181-
FiltersSchema.from_cli_params(cli_filter)
197+
cli_excludes = ()
198+
FiltersSchema.from_cli_params(cli_filter, cli_excludes)
182199

183200
with pytest.raises(ValueError):
184201
cli_filter = ("resource_types:test,freddy",)
185-
FiltersSchema.from_cli_params(cli_filter)
202+
cli_excludes = ()
203+
FiltersSchema.from_cli_params(cli_filter, cli_excludes)
186204

187205
with pytest.raises(ValueError):
188206
cli_filter = ("resource_types:test", "resource_types:freddy")
189-
FiltersSchema.from_cli_params(cli_filter)
207+
cli_excludes = ()
208+
FiltersSchema.from_cli_params(cli_filter, cli_excludes)
190209

191210
cli_filter = ("resource_types:test",)
192-
filter_schema = FiltersSchema.from_cli_params(cli_filter)
211+
cli_excludes = ()
212+
filter_schema = FiltersSchema.from_cli_params(cli_filter, cli_excludes)
193213
assert len(filter_schema.tags) == 0
194214
assert len(filter_schema.models) == 0
195215
assert len(filter_schema.owners) == 0
@@ -201,7 +221,8 @@ def test_resource_types_key_from_cli_params():
201221
assert filter_schema.resource_types[0].values == ["test"]
202222

203223
cli_filter = ("resource_types:test,model",)
204-
filter_schema = FiltersSchema.from_cli_params(cli_filter)
224+
cli_excludes = ()
225+
filter_schema = FiltersSchema.from_cli_params(cli_filter, cli_excludes)
205226
assert len(filter_schema.tags) == 0
206227
assert len(filter_schema.models) == 0
207228
assert len(filter_schema.owners) == 0
@@ -213,7 +234,8 @@ def test_resource_types_key_from_cli_params():
213234
assert sorted(filter_schema.resource_types[0].values) == sorted(["test", "model"])
214235

215236
cli_filter = ("resource_types:test", "resource_types:model")
216-
filter_schema = FiltersSchema.from_cli_params(cli_filter)
237+
cli_excludes = ()
238+
filter_schema = FiltersSchema.from_cli_params(cli_filter, cli_excludes)
217239
assert len(filter_schema.tags) == 0
218240
assert len(filter_schema.models) == 0
219241
assert len(filter_schema.owners) == 0
@@ -228,7 +250,8 @@ def test_resource_types_key_from_cli_params():
228250

229251
def test_unsupported_key_from_cli_params():
230252
cli_filter = ("fake",)
231-
filter_schema = FiltersSchema.from_cli_params(cli_filter)
253+
cli_excludes = ()
254+
filter_schema = FiltersSchema.from_cli_params(cli_filter, cli_excludes)
232255
assert len(filter_schema.tags) == 0
233256
assert len(filter_schema.owners) == 0
234257
assert len(filter_schema.models) == 0
@@ -241,7 +264,8 @@ def test_unsupported_key_from_cli_params():
241264

242265
def test_multiple_keys_from_cli_params():
243266
cli_filter = ("tags:tag1", "owners:freddy,dredd")
244-
filter_schema = FiltersSchema.from_cli_params(cli_filter)
267+
cli_excludes = ()
268+
filter_schema = FiltersSchema.from_cli_params(cli_filter, cli_excludes)
245269
assert len(filter_schema.tags) == 1
246270
assert filter_schema.tags[0].values == ["tag1"]
247271
assert len(filter_schema.owners) == 1
@@ -252,3 +276,37 @@ def test_multiple_keys_from_cli_params():
252276
["fail", "error", "runtime error", "warn"]
253277
)
254278
assert len(filter_schema.resource_types) == 0
279+
280+
281+
def test_exclude_filters():
282+
cli_filter = ("tags:tag1",)
283+
cli_excludes = ("tags:tag2",)
284+
filter_schema = FiltersSchema.from_cli_params(cli_filter, cli_excludes)
285+
assert len(filter_schema.tags) == 2
286+
assert filter_schema.tags[0].values == ["tag1"]
287+
assert filter_schema.tags[0].type == FilterType.IS
288+
assert filter_schema.tags[1].values == ["tag2"]
289+
assert filter_schema.tags[1].type == FilterType.IS_NOT
290+
assert len(filter_schema.owners) == 0
291+
assert len(filter_schema.models) == 0
292+
assert len(filter_schema.statuses) == 1
293+
assert sorted(filter_schema.statuses[0].values) == sorted(
294+
["fail", "error", "runtime error", "warn"]
295+
)
296+
assert len(filter_schema.resource_types) == 0
297+
298+
299+
def test_exclude_statuses_filters():
300+
cli_filters = ()
301+
cli_excludes = ("statuses:fail",)
302+
filter_schema = FiltersSchema.from_cli_params(cli_filters, cli_excludes)
303+
assert len(filter_schema.tags) == 0
304+
assert len(filter_schema.models) == 0
305+
assert len(filter_schema.owners) == 0
306+
assert len(filter_schema.statuses) == 2
307+
assert filter_schema.statuses[0].values == ["fail"]
308+
assert filter_schema.statuses[0].type == FilterType.IS_NOT
309+
assert sorted(filter_schema.statuses[1].values) == sorted(
310+
["fail", "error", "runtime error", "warn"]
311+
)
312+
assert filter_schema.statuses[1].type == FilterType.IS

0 commit comments

Comments
 (0)