@cryptotaxi247 / netdata-1 / commits / 0ab782630

Remove the overview section from cloud notif. integrations (#18754)

Co-authored-by: ilyam8 <ilya@netdata.cloud>

Fotis Voutsas committed Oct 14, 2024 at 11:23 UTC 0ab7826301d458bb384494be93e362feebad931e
7 files changed +338 -153
integrations/cloud-notifications/metadata.yaml
-42
@@ -11,9 +11,6 @@
11 - mobile-app
12 - phone
13 - personal-notifications
14 - overview:
15 - notification_description: "You can configure notification delivery to the Netdata Mobile Application from the Netdata Cloud UI."
16 - notification_limitations: ""
14 setup:
15 description: |
16 ### Prerequisites
@@ -44,9 +41,6 @@
41 keywords:
42 - discord
43 - community
47 - overview:
48 - notification_description: "You can configure notification delivery to your Discord server from the Netdata Cloud UI."
49 - notification_limitations: ""
44 setup:
45 description: |
46 ### Prerequisites
@@ -85,9 +79,6 @@
79 icon_filename: "pagerduty.png"
80 keywords:
81 - pagerduty
88 - overview:
89 - notification_description: "You can configure notification delivery to PagerDuty from the Netdata Cloud UI."
90 - notification_limitations: ""
82 setup:
83 description: |
84 ### Prerequisites
@@ -127,9 +118,6 @@
118 icon_filename: "slack.png"
119 keywords:
120 - slack
130 - overview:
131 - notification_description: "You can configure notification delivery to Slack from the Netdata Cloud UI."
132 - notification_limitations: ""
121 setup:
122 description: |
123 ### Prerequisites
@@ -175,9 +163,6 @@
163 keywords:
164 - opsgenie
165 - atlassian
178 - overview:
179 - notification_description: "You can configure notification delivery to Opsgenie from the Netdata Cloud UI."
180 - notification_limitations: ""
166 setup:
167 description: |
168 ### Prerequisites
@@ -215,9 +200,6 @@
200 icon_filename: "mattermost.png"
201 keywords:
202 - mattermost
218 - overview:
219 - notification_description: "You can configure notification delivery to Mattermost from the Netdata Cloud UI."
220 - notification_limitations: ""
203 setup:
204 description: |
205 ### Prerequisites
@@ -260,9 +242,6 @@
242 icon_filename: "rocketchat.png"
243 keywords:
244 - rocketchat
263 - overview:
264 - notification_description: "You can configure notification delivery to RocketChat from the Netdata Cloud UI."
265 - notification_limitations: ""
245 setup:
246 description: |
247 ### Prerequisites
@@ -306,9 +285,6 @@
285 icon_filename: "awssns.png"
286 keywords:
287 - awssns
309 - overview:
310 - notification_description: "You can configure notification delivery to AWS SNS from the Netdata Cloud UI."
311 - notification_limitations: ""
288 setup:
289 description: |
290 ### Prerequisites
@@ -351,9 +327,6 @@
327 keywords:
328 - microsoft
329 - teams
354 - overview:
355 - notification_description: "You can configure notification delivery to a Microsoft Teams channel from the Netdata Cloud UI."
356 - notification_limitations: ""
330 setup:
331 description: |
332 ### Prerequisites
@@ -396,9 +369,6 @@
369 icon_filename: "telegram.svg"
370 keywords:
371 - Telegram
399 - overview:
400 - notification_description: "You can configure notification delivery to Telegram from the Netdata Cloud UI."
401 - notification_limitations: ""
372 setup:
373 description: |
374 ### Prerequisites
@@ -441,9 +411,6 @@
411 icon_filename: "splunk-black.svg"
412 keywords:
413 - Splunk
444 - overview:
445 - notification_description: "You can configure notification delivery to Splunk from the Netdata Cloud UI."
446 - notification_limitations: ""
414 setup:
415 description: |
416 ### Prerequisites
@@ -479,9 +446,6 @@
446 - VictorOps
447 - Splunk
448 - On-Call
482 - overview:
483 - notification_description: "You can configure notification delivery to Splunk On-Call/VictorOps from the Netdata Cloud UI."
484 - notification_limitations: ""
449 setup:
450 description: |
451 ### Prerequisites
@@ -515,9 +479,6 @@
479 keywords:
480 - generic webhooks
481 - webhooks
518 - overview:
519 - notification_description: "You can configure notification delivery to a webhook using a predefined schema from the Netdata Cloud UI."
520 - notification_limitations: ""
482 setup:
483 description: |
484 ### Prerequisites
@@ -765,9 +726,6 @@
726 icon_filename: "ilert.svg"
727 keywords:
728 - ilert
768 - overview:
769 - notification_description: "You can configure notification delivery to ilert from the Netdata Cloud UI."
770 - notification_limitations: ""
729 setup:
730 description: |
731 ### Prerequisites
integrations/gen_docs_integrations.py
+90 -38
@@ -1,7 +1,7 @@
1 import json
2 +import re
3 import shutil
4 from pathlib import Path
4 -import re
5
6 # Dictionary responsible for making the symbolic links at the end of the script's run.
7 symlink_dict = {}
@@ -29,6 +29,7 @@ def cleanup():
29 if "integrations" in str(element) and not "metadata.yaml" in str(element):
30 shutil.rmtree(element)
31
32 +
33 def generate_category_from_name(category_fragment, category_array):
34 """
35 Takes a category ID in splitted form ("." as delimiter) and the array of the categories, and returns the proper category name that Learn expects.
@@ -46,7 +47,7 @@ def generate_category_from_name(category_fragment, category_array):
47 try:
48 # print("equals")
49 # print(fragment, category_fragment[i+1])
49 - dummy_id = dummy_id + "." + category_fragment[i+1]
50 + dummy_id = dummy_id + "." + category_fragment[i + 1]
51 # print(dummy_id)
52 except IndexError:
53 return category_name.split("/", 1)[1]
@@ -79,10 +80,10 @@ def add_custom_edit_url(markdown_string, meta_yaml_link, sidebar_label_string, m
80 if mode == 'default':
81 path_to_md_file = f'{meta_yaml_link.replace("/metadata.yaml", "")}/integrations/{clean_string(sidebar_label_string)}'
82
82 - elif mode == 'cloud-notifications':
83 + elif mode == 'cloud-notification':
84 path_to_md_file = meta_yaml_link.replace("metadata.yaml", f'integrations/{clean_string(sidebar_label_string)}')
85
85 - elif mode == 'agent-notifications':
86 + elif mode == 'agent-notification':
87 path_to_md_file = meta_yaml_link.replace("metadata.yaml", "README")
88
89 elif mode == 'cloud-authentication':
@@ -122,23 +123,29 @@ def read_integrations_js(path_to_file):
123 print("Exception", e)
124
125
125 -def create_overview(integration, filename):
126 +def create_overview(integration, filename, overview_key_name="overview"):
127 + # empty overview_key_name to have only image on overview
128 + if not overview_key_name:
129 + return f"""# {integration['meta']['name']}
130
127 - split = re.split(r'(#.*\n)', integration['overview'], 1)
131 +<img src="https://netdata.cloud/img/{filename}" width="150"/>
132 +"""
133 +
134 + split = re.split(r'(#.*\n)', integration[overview_key_name], 1)
135
136 first_overview_part = split[1]
137 rest_overview_part = split[2]
138
132 - if len(filename) > 0:
133 - return f"""{first_overview_part}
139 + if not filename:
140 + return f"""{first_overview_part}{rest_overview_part}
141 +"""
142 +
143 + return f"""{first_overview_part}
144
145 <img src="https://netdata.cloud/img/{filename}" width="150"/>
146
147 {rest_overview_part}
148 """
139 - else:
140 - return f"""{first_overview_part}{rest_overview_part}
141 -"""
149
150
151 def build_readme_from_integration(integration, mode=''):
@@ -150,7 +157,8 @@ def build_readme_from_integration(integration, mode=''):
157 meta_yaml = integration['edit_link'].replace("blob", "edit")
158 sidebar_label = integration['meta']['monitored_instance']['name']
159 learn_rel_path = generate_category_from_name(
153 - integration['meta']['monitored_instance']['categories'][0].split("."), categories).replace("Data Collection", "Collecting Metrics")
160 + integration['meta']['monitored_instance']['categories'][0].split("."), categories).replace(
161 + "Data Collection", "Collecting Metrics")
162 most_popular = integration['meta']['most_popular']
163
164 # build the markdown string
@@ -221,7 +229,7 @@ endmeta-->
229 print("Exception in exporter md construction", e, integration['id'])
230
231 # NOTIFICATIONS
224 - elif mode == 'notification':
232 + elif mode == 'agent-notification':
233 try:
234 # initiate the variables for the notification method
235 meta_yaml = integration['edit_link'].replace("blob", "edit")
@@ -238,7 +246,7 @@ learn_rel_path: "{learn_rel_path.replace("notifications", "Alerts & Notification
246 message: "DO NOT EDIT THIS FILE DIRECTLY, IT IS GENERATED BY THE NOTIFICATION'S metadata.yaml FILE"
247 endmeta-->
248
241 -{create_overview(integration, integration['meta']['icon_filename'])}"""
249 +{create_overview(integration, integration['meta']['icon_filename'], "overview")}"""
250
251 if integration['setup']:
252 md += f"""
@@ -252,7 +260,39 @@ endmeta-->
260
261 except Exception as e:
262 print("Exception in notification md construction", e, integration['id'])
255 -
263 +
264 + elif mode == 'cloud-notification':
265 + try:
266 + # initiate the variables for the notification method
267 + meta_yaml = integration['edit_link'].replace("blob", "edit")
268 + sidebar_label = integration['meta']['name']
269 + learn_rel_path = generate_category_from_name(integration['meta']['categories'][0].split("."), categories)
270 +
271 + # build the markdown string
272 + md = \
273 + f"""<!--startmeta
274 +meta_yaml: "{meta_yaml}"
275 +sidebar_label: "{sidebar_label}"
276 +learn_status: "Published"
277 +learn_rel_path: "{learn_rel_path.replace("notifications", "Alerts & Notifications/Notifications")}"
278 +message: "DO NOT EDIT THIS FILE DIRECTLY, IT IS GENERATED BY THE NOTIFICATION'S metadata.yaml FILE"
279 +endmeta-->
280 +
281 +{create_overview(integration, integration['meta']['icon_filename'], "")}"""
282 +
283 + if integration['setup']:
284 + md += f"""
285 +{integration['setup']}
286 +"""
287 +
288 + if integration['troubleshooting']:
289 + md += f"""
290 +{integration['troubleshooting']}
291 +"""
292 +
293 + except Exception as e:
294 + print("Exception in notification md construction", e, integration['id'])
295 +
296 # AUTHENTICATIONS
297 elif mode == 'authentication':
298 if True:
@@ -339,27 +379,35 @@ def write_to_file(path, md, meta_yaml, sidebar_label, community, mode='default')
379 except KeyError:
380 # We don't need to print something here.
381 pass
342 - elif mode == 'notification':
382 + elif mode == 'cloud-notification':
383
344 - if "cloud-notifications" in path:
345 - # for cloud notifications we generate them near their metadata.yaml
346 - name = clean_string(integration['meta']['name'])
384 + # for cloud notifications we generate them near their metadata.yaml
385 + name = clean_string(integration['meta']['name'])
386
348 - if not Path(f'{path}/integrations').exists():
349 - Path(f'{path}/integrations').mkdir()
387 + if not Path(f'{path}/integrations').exists():
388 + Path(f'{path}/integrations').mkdir()
389 +
390 + # proper_edit_name = meta_yaml.replace(
391 + # "metadata.yaml", f'integrations/{clean_string(sidebar_label)}.md\"')
392
351 - # proper_edit_name = meta_yaml.replace(
352 - # "metadata.yaml", f'integrations/{clean_string(sidebar_label)}.md\"')
393 + md = add_custom_edit_url(md, meta_yaml, sidebar_label, mode='cloud-notification')
394
354 - md = add_custom_edit_url(md, meta_yaml, sidebar_label, mode='cloud-notifications')
395 + finalpath = f'{path}/integrations/{name}.md'
396 +
397 + try:
398 + clean_and_write(
399 + md,
400 + Path(finalpath)
401 + )
402 + except FileNotFoundError as e:
403 + print("Exception in writing to file", e)
404 + elif mode == 'agent-notification':
405 + # add custom_edit_url as the md file, so we can have uniqueness in the ingest script
406 + # afterwards the ingest will replace this metadata with meta_yaml
407
356 - finalpath = f'{path}/integrations/{name}.md'
357 - else:
358 - # add custom_edit_url as the md file, so we can have uniqueness in the ingest script
359 - # afterwards the ingest will replace this metadata with meta_yaml
360 - md = add_custom_edit_url(md, meta_yaml, sidebar_label, mode='agent-notifications')
408 + md = add_custom_edit_url(md, meta_yaml, sidebar_label, mode='agent-notification')
409
362 - finalpath = f'{path}/README.md'
410 + finalpath = f'{path}/README.md'
411
412 try:
413 clean_and_write(
@@ -383,7 +431,7 @@ def write_to_file(path, md, meta_yaml, sidebar_label, community, mode='default')
431 md = add_custom_edit_url(md, meta_yaml, sidebar_label, mode='cloud-authentication')
432
433 finalpath = f'{path}/integrations/{name}.md'
386 -
434 +
435 try:
436 clean_and_write(
437 md,
@@ -422,7 +470,6 @@ cleanup()
470
471 categories, integrations = read_integrations_js('integrations/integrations.js')
472
425 -
473 # Iterate through every integration
474 for integration in integrations:
475
@@ -442,20 +489,25 @@ for integration in integrations:
489 path = build_path(meta_yaml)
490 write_to_file(path, md, meta_yaml, sidebar_label, community)
491
445 - # kind of specific if clause, so we can avoid running excessive code in the go repo
446 - elif integration['integration_type'] == "notification":
492 + elif integration['integration_type'] == "agent_notification":
493 +
494 + meta_yaml, sidebar_label, learn_rel_path, md, community = build_readme_from_integration(
495 + integration, mode='agent-notification')
496 + path = build_path(meta_yaml)
497 + write_to_file(path, md, meta_yaml, sidebar_label, community, mode='agent-notification')
498 +
499 + elif integration['integration_type'] == "cloud_notification":
500
501 meta_yaml, sidebar_label, learn_rel_path, md, community = build_readme_from_integration(
449 - integration, mode='notification')
502 + integration, mode='cloud-notification')
503 path = build_path(meta_yaml)
451 - write_to_file(path, md, meta_yaml, sidebar_label, community, mode='notification')
504 + write_to_file(path, md, meta_yaml, sidebar_label, community, mode='cloud-notification')
505
506 elif integration['integration_type'] == "authentication":
507
508 meta_yaml, sidebar_label, learn_rel_path, md, community = build_readme_from_integration(
509 integration, mode='authentication')
510 path = build_path(meta_yaml)
458 - write_to_file(path, md, meta_yaml, sidebar_label, community, mode='authentication')
459 -
511 + write_to_file(path, md, meta_yaml, sidebar_label, community, mode='authentication')
512
513 make_symlinks(symlink_dict)
integrations/gen_integrations.py
+163 -54
@@ -4,7 +4,6 @@ import json
4 import os
5 import re
6 import sys
7 -
7 from copy import deepcopy
8 from pathlib import Path
9
@@ -40,8 +39,11 @@ EXPORTER_SOURCES = [
39 (AGENT_REPO, REPO_PATH / 'src' / 'exporting', True),
40 ]
41
43 -NOTIFICATION_SOURCES = [
42 +AGENT_NOTIFICATION_SOURCES = [
43 (AGENT_REPO, REPO_PATH / 'src' / 'health' / 'notifications', True),
44 +]
45 +
46 +CLOUD_NOTIFICATION_SOURCES = [
47 (AGENT_REPO, INTEGRATIONS_PATH / 'cloud-notifications' / 'metadata.yaml', False),
48 ]
49
@@ -64,12 +66,17 @@ EXPORTER_RENDER_KEYS = [
66 'troubleshooting',
67 ]
68
67 -NOTIFICATION_RENDER_KEYS = [
69 +AGENT_NOTIFICATION_RENDER_KEYS = [
70 'overview',
71 'setup',
72 'troubleshooting',
73 ]
74
75 +CLOUD_NOTIFICATION_RENDER_KEYS = [
76 + 'setup',
77 + 'troubleshooting',
78 +]
79 +
80 AUTHENTICATION_RENDER_KEYS = [
81 'overview',
82 'setup',
@@ -85,18 +92,18 @@ DEBUG = os.environ.get('DEBUG', False)
92
93 def debug(msg):
94 if GITHUB_ACTIONS:
88 - print(f':debug:{ msg }')
95 + print(f':debug:{msg}')
96 elif DEBUG:
90 - print(f'>>> { msg }')
97 + print(f'>>> {msg}')
98 else:
99 pass
100
101
102 def warn(msg, path):
103 if GITHUB_ACTIONS:
97 - print(f':warning file={ path }:{ msg }')
104 + print(f':warning file={path}:{msg}')
105 else:
99 - print(f'!!! WARNING:{ path }:{ msg }')
106 + print(f'!!! WARNING:{path}:{msg}')
107
108
109 def retrieve_from_filesystem(uri):
@@ -122,8 +129,13 @@ EXPORTER_VALIDATOR = Draft7Validator(
129 registry=registry,
130 )
131
125 -NOTIFICATION_VALIDATOR = Draft7Validator(
126 - {'$ref': './notification.json#'},
132 +AGENT_NOTIFICATION_VALIDATOR = Draft7Validator(
133 + {'$ref': './agent_notification.json#'},
134 + registry=registry,
135 +)
136 +
137 +CLOUD_NOTIFICATION_VALIDATOR = Draft7Validator(
138 + {'$ref': './cloud_notification.json#'},
139 registry=registry,
140 )
141
@@ -209,19 +221,19 @@ def load_yaml(src):
221 yaml = YAML(typ='safe')
222
223 if not src.is_file():
212 - warn(f'{ src } is not a file.', src)
224 + warn(f'{src} is not a file.', src)
225 return False
226
227 try:
228 contents = src.read_text()
229 except (IOError, OSError):
218 - warn(f'Failed to read { src }.', src)
230 + warn(f'Failed to read {src}.', src)
231 return False
232
233 try:
234 data = yaml.load(contents)
235 except YAMLError:
224 - warn(f'Failed to parse { src } as YAML.', src)
236 + warn(f'Failed to parse {src} as YAML.', src)
237 return False
238
239 return data
@@ -236,7 +248,7 @@ def load_categories():
248 try:
249 CATEGORY_VALIDATOR.validate(categories)
250 except ValidationError:
239 - warn(f'Failed to validate { CATEGORIES_FILE } against the schema.', CATEGORIES_FILE)
251 + warn(f'Failed to validate {CATEGORIES_FILE} against the schema.', CATEGORIES_FILE)
252 sys.exit(1)
253
254 return categories
@@ -248,7 +260,7 @@ def load_collectors():
260 entries = get_collector_metadata_entries()
261
262 for repo, path in entries:
251 - debug(f'Loading { path }.')
263 + debug(f'Loading {path}.')
264 data = load_yaml(path)
265
266 if not data:
@@ -257,7 +269,7 @@ def load_collectors():
269 try:
270 COLLECTOR_VALIDATOR.validate(data)
271 except ValidationError:
260 - warn(f'Failed to validate { path } against the schema.', path)
272 + warn(f'Failed to validate {path} against the schema.', path)
273 continue
274
275 for idx, item in enumerate(data['modules']):
@@ -273,7 +285,7 @@ def load_collectors():
285
286 def _load_deploy_file(file, repo):
287 ret = []
276 - debug(f'Loading { file }.')
288 + debug(f'Loading {file}.')
289 data = load_yaml(file)
290
291 if not data:
@@ -282,7 +294,7 @@ def _load_deploy_file(file, repo):
294 try:
295 DEPLOY_VALIDATOR.validate(data)
296 except ValidationError:
285 - warn(f'Failed to validate { file } against the schema.', file)
297 + warn(f'Failed to validate {file} against the schema.', file)
298 return []
299
300 for idx, item in enumerate(data):
@@ -309,7 +321,7 @@ def load_deploy():
321
322
323 def _load_exporter_file(file, repo):
312 - debug(f'Loading { file }.')
324 + debug(f'Loading {file}.')
325 data = load_yaml(file)
326
327 if not data:
@@ -318,7 +330,7 @@ def _load_exporter_file(file, repo):
330 try:
331 EXPORTER_VALIDATOR.validate(data)
332 except ValidationError:
321 - warn(f'Failed to validate { file } against the schema.', file)
333 + warn(f'Failed to validate {file} against the schema.', file)
334 return []
335
336 if 'id' in data:
@@ -354,21 +366,21 @@ def load_exporters():
366 return ret
367
368
357 -def _load_notification_file(file, repo):
358 - debug(f'Loading { file }.')
369 +def _load_agent_notification_file(file, repo):
370 + debug(f'Loading {file}.')
371 data = load_yaml(file)
372
373 if not data:
374 return []
375
376 try:
365 - NOTIFICATION_VALIDATOR.validate(data)
377 + AGENT_NOTIFICATION_VALIDATOR.validate(data)
378 except ValidationError:
367 - warn(f'Failed to validate { file } against the schema.', file)
379 + warn(f'Failed to validate {file} against the schema.', file)
380 return []
381
382 if 'id' in data:
371 - data['integration_type'] = 'notification'
383 + data['integration_type'] = 'agent_notification'
384 data['_src_path'] = file
385 data['_repo'] = repo
386 data['_index'] = 0
@@ -378,7 +390,7 @@ def _load_notification_file(file, repo):
390 ret = []
391
392 for idx, item in enumerate(data):
381 - item['integration_type'] = 'notification'
393 + item['integration_type'] = 'agent_notification'
394 item['_src_path'] = file
395 item['_repo'] = repo
396 item['_index'] = idx
@@ -387,20 +399,67 @@ def _load_notification_file(file, repo):
399 return ret
400
401
390 -def load_notifications():
402 +def _load_cloud_notification_file(file, repo):
403 + debug(f'Loading {file}.')
404 + data = load_yaml(file)
405 +
406 + if not data:
407 + return []
408 +
409 + try:
410 + CLOUD_NOTIFICATION_VALIDATOR.validate(data)
411 + except ValidationError:
412 + warn(f'Failed to validate {file} against the schema.', file)
413 + return []
414 +
415 + if 'id' in data:
416 + data['integration_type'] = 'cloud_notification'
417 + data['_src_path'] = file
418 + data['_repo'] = repo
419 + data['_index'] = 0
420 +
421 + return [data]
422 + else:
423 + ret = []
424 +
425 + for idx, item in enumerate(data):
426 + item['integration_type'] = 'cloud_notification'
427 + item['_src_path'] = file
428 + item['_repo'] = repo
429 + item['_index'] = idx
430 + ret.append(item)
431 +
432 + return ret
433 +
434 +
435 +def load_agent_notifications():
436 + ret = []
437 +
438 + for repo, path, match in AGENT_NOTIFICATION_SOURCES:
439 + if match and path.exists() and path.is_dir():
440 + for file in path.glob(METADATA_PATTERN):
441 + ret.extend(_load_agent_notification_file(file, repo))
442 + elif not match and path.exists() and path.is_file():
443 + ret.extend(_load_agent_notification_file(path, repo))
444 +
445 + return ret
446 +
447 +
448 +def load_cloud_notifications():
449 ret = []
450
393 - for repo, path, match in NOTIFICATION_SOURCES:
451 + for repo, path, match in CLOUD_NOTIFICATION_SOURCES:
452 if match and path.exists() and path.is_dir():
453 for file in path.glob(METADATA_PATTERN):
396 - ret.extend(_load_notification_file(file, repo))
454 + ret.extend(_load_cloud_notification_file(file, repo))
455 elif not match and path.exists() and path.is_file():
398 - ret.extend(_load_notification_file(path, repo))
456 + ret.extend(_load_cloud_notification_file(path, repo))
457
458 return ret
459
460 +
461 def _load_authentication_file(file, repo):
403 - debug(f'Loading { file }.')
462 + debug(f'Loading {file}.')
463 data = load_yaml(file)
464
465 if not data:
@@ -409,7 +468,7 @@ def _load_authentication_file(file, repo):
468 try:
469 AUTHENTICATION_VALIDATOR.validate(data)
470 except ValidationError:
412 - warn(f'Failed to validate { file } against the schema.', file)
471 + warn(f'Failed to validate {file} against the schema.', file)
472 return []
473
474 if 'id' in data:
@@ -453,13 +512,13 @@ def make_id(meta):
512 else:
513 instance_name = '000_unknown'
514
456 - return f'{ meta["plugin_name"] }-{ meta["module_name"] }-{ instance_name }'
515 + return f'{meta["plugin_name"]}-{meta["module_name"]}-{instance_name}'
516
517
518 def make_edit_link(item):
519 item_path = item['_src_path'].relative_to(REPO_PATH)
520
462 - return f'https://github.com/{ item["_repo"] }/blob/master/{ item_path }'
521 + return f'https://github.com/{item["_repo"]}/blob/master/{item_path}'
522
523
524 def sort_integrations(integrations):
@@ -474,7 +533,9 @@ def dedupe_integrations(integrations, ids):
533 for i in integrations:
534 if ids.get(i['id'], False):
535 first_path, first_index = ids[i['id']]
477 - warn(f'Duplicate integration ID found at { i["_src_path"] } index { i["_index"] } (original definition at { first_path } index { first_index }), ignoring that integration.', i['_src_path'])
536 + warn(
537 + f'Duplicate integration ID found at {i["_src_path"]} index {i["_index"]} (original definition at {first_path} index {first_index}), ignoring that integration.',
538 + i['_src_path'])
539 else:
540 tmp_integrations.append(i)
541 ids[i['id']] = (i['_src_path'], i['_index'])
@@ -504,7 +565,7 @@ def render_collectors(categories, collectors, ids):
565 idmap = {i['id']: i for i in collectors}
566
567 for item in collectors:
507 - debug(f'Processing { item["id"] }.')
568 + debug(f'Processing {item["id"]}.')
569
570 item['edit_link'] = make_edit_link(item)
571
@@ -516,7 +577,7 @@ def render_collectors(categories, collectors, ids):
577 res_id = make_id(res)
578
579 if res_id not in idmap.keys():
519 - warn(f'Could not find related integration { res_id }, ignoring it.', item['_src_path'])
580 + warn(f'Could not find related integration {res_id}, ignoring it.', item['_src_path'])
581 continue
582
583 related.append({
@@ -532,17 +593,19 @@ def render_collectors(categories, collectors, ids):
593 actual_cats = item_cats & valid_cats
594
595 if bogus_cats:
535 - warn(f'Ignoring invalid categories: { ", ".join(bogus_cats) }', item["_src_path"])
596 + warn(f'Ignoring invalid categories: {", ".join(bogus_cats)}', item["_src_path"])
597
598 if not item_cats:
599 item['meta']['monitored_instance']['categories'] = list(default_cats)
539 - warn(f'{ item["id"] } does not list any caregories, adding it to: { default_cats }', item["_src_path"])
600 + warn(f'{item["id"]} does not list any caregories, adding it to: {default_cats}', item["_src_path"])
601 else:
541 - item['meta']['monitored_instance']['categories'] = [x for x in item['meta']['monitored_instance']['categories'] if x in list(actual_cats)]
602 + item['meta']['monitored_instance']['categories'] = [x for x in
603 + item['meta']['monitored_instance']['categories'] if
604 + x in list(actual_cats)]
605
606 for scope in item['metrics']['scopes']:
607 if scope['name'] == 'global':
545 - scope['name'] = f'{ item["meta"]["monitored_instance"]["name"] } instance'
608 + scope['name'] = f'{item["meta"]["monitored_instance"]["name"]} instance'
609
610 for cfg_example in item['setup']['configuration']['examples']['list']:
611 if 'folding' not in cfg_example:
@@ -552,7 +615,7 @@ def render_collectors(categories, collectors, ids):
615
616 for key in COLLECTOR_RENDER_KEYS:
617 if key in item.keys():
555 - template = get_jinja_env().get_template(f'{ key }.md')
618 + template = get_jinja_env().get_template(f'{key}.md')
619 data = template.render(entry=item, related=related, clean=False)
620 clean_data = template.render(entry=item, related=related, clean=True)
621
@@ -589,7 +652,7 @@ def render_deploy(distros, categories, deploy, ids):
652 template = get_jinja_env().get_template('platform_info.md')
653
654 for item in deploy:
592 - debug(f'Processing { item["id"] }.')
655 + debug(f'Processing {item["id"]}.')
656 item['edit_link'] = make_edit_link(item)
657 clean_item = deepcopy(item)
658
@@ -646,7 +709,7 @@ def render_exporters(categories, exporters, ids):
709
710 for key in EXPORTER_RENDER_KEYS:
711 if key in item.keys():
649 - template = get_jinja_env().get_template(f'{ key }.md')
712 + template = get_jinja_env().get_template(f'{key}.md')
713 data = template.render(entry=item, clean=False)
714 clean_data = template.render(entry=item, clean=True)
715
@@ -670,7 +733,7 @@ def render_exporters(categories, exporters, ids):
733 return exporters, clean_exporters, ids
734
735
673 -def render_notifications(categories, notifications, ids):
736 +def render_agent_notifications(categories, notifications, ids):
737 debug('Sorting notifications.')
738
739 sort_integrations(notifications)
@@ -686,9 +749,52 @@ def render_notifications(categories, notifications, ids):
749
750 clean_item = deepcopy(item)
751
689 - for key in NOTIFICATION_RENDER_KEYS:
752 + for key in AGENT_NOTIFICATION_RENDER_KEYS:
753 if key in item.keys():
691 - template = get_jinja_env().get_template(f'{ key }.md')
754 + template = get_jinja_env().get_template(f'{key}.md')
755 + data = template.render(entry=item, clean=False)
756 +
757 + clean_data = template.render(entry=item, clean=True)
758 +
759 + if 'variables' in item['meta']:
760 + template = get_jinja_env().from_string(data)
761 + data = template.render(variables=item['meta']['variables'], clean=False)
762 + template = get_jinja_env().from_string(clean_data)
763 + clean_data = template.render(variables=item['meta']['variables'], clean=True)
764 + else:
765 + data = ''
766 + clean_data = ''
767 +
768 + item[key] = data
769 + clean_item[key] = clean_data
770 +
771 + for k in ['_src_path', '_repo', '_index']:
772 + del item[k], clean_item[k]
773 +
774 + clean_notifications.append(clean_item)
775 +
776 + return notifications, clean_notifications, ids
777 +
778 +
779 +def render_cloud_notifications(categories, notifications, ids):
780 + debug('Sorting notifications.')
781 +
782 + sort_integrations(notifications)
783 +
784 + debug('Checking notification ids.')
785 +
786 + notifications, ids = dedupe_integrations(notifications, ids)
787 +
788 + clean_notifications = []
789 +
790 + for item in notifications:
791 + item['edit_link'] = make_edit_link(item)
792 +
793 + clean_item = deepcopy(item)
794 +
795 + for key in CLOUD_NOTIFICATION_RENDER_KEYS:
796 + if key in item.keys():
797 + template = get_jinja_env().get_template(f'{key}.md')
798 data = template.render(entry=item, clean=False)
799 clean_data = template.render(entry=item, clean=True)
800
@@ -729,9 +835,9 @@ def render_authentications(categories, authentications, ids):
835 clean_item = deepcopy(item)
836
837 for key in AUTHENTICATION_RENDER_KEYS:
732 -
838 +
839 if key in item.keys():
734 - template = get_jinja_env().get_template(f'{ key }.md')
840 + template = get_jinja_env().get_template(f'{key}.md')
841 data = template.render(entry=item, clean=False)
842 clean_data = template.render(entry=item, clean=True)
843
@@ -746,7 +852,7 @@ def render_authentications(categories, authentications, ids):
852
853 item[key] = data
854 clean_item[key] = clean_data
749 -
855 +
856 for k in ['_src_path', '_repo', '_index']:
857 del item[k], clean_item[k]
858
@@ -777,20 +883,23 @@ def main():
883 collectors = load_collectors()
884 deploy = load_deploy()
885 exporters = load_exporters()
780 - notifications = load_notifications()
886 + agent_notifications = load_agent_notifications()
887 + cloud_notifications = load_cloud_notifications()
888 authentications = load_authentications()
889
890 collectors, clean_collectors, ids = render_collectors(categories, collectors, dict())
891 deploy, clean_deploy, ids = render_deploy(distros, categories, deploy, ids)
892 exporters, clean_exporters, ids = render_exporters(categories, exporters, ids)
786 - notifications, clean_notifications, ids = render_notifications(categories, notifications, ids)
893 + agent_notifications, clean_agent_notifications, ids = render_agent_notifications(categories, agent_notifications,
894 + ids)
895 + cloud_notifications, clean_cloud_notifications, ids = render_cloud_notifications(categories, cloud_notifications,
896 + ids)
897 authentications, clean_authentications, ids = render_authentications(categories, authentications, ids)
898
789 -
790 - integrations = collectors + deploy + exporters + notifications + authentications
899 + integrations = collectors + deploy + exporters + agent_notifications + cloud_notifications + authentications
900 render_integrations(categories, integrations)
901
793 - clean_integrations = clean_collectors + clean_deploy + clean_exporters + clean_notifications + clean_authentications
902 + clean_integrations = clean_collectors + clean_deploy + clean_exporters + clean_agent_notifications + clean_cloud_notifications + clean_authentications
903 render_json(categories, clean_integrations)
904
905
integrations/schemas/agent_notification.json renamed
+14 -14
@@ -46,20 +46,20 @@
46 ]
47 },
48 "global_setup": {
49 - "type": "object",
50 - "description": "Flags that show which global setup sections are relevant for this notification method.",
51 - "properties": {
52 - "severity_filtering": {
53 - "type": "boolean"
54 - },
55 - "http_proxy": {
56 - "type": "boolean"
57 - }
49 + "type": "object",
50 + "description": "Flags that show which global setup sections are relevant for this notification method.",
51 + "properties": {
52 + "severity_filtering": {
53 + "type": "boolean"
54 },
59 - "required": [
60 - "severity_filtering",
61 - "http_proxy"
62 - ]
55 + "http_proxy": {
56 + "type": "boolean"
57 + }
58 + },
59 + "required": [
60 + "severity_filtering",
61 + "http_proxy"
62 + ]
63 },
64 "setup": {
65 "oneOf": [
@@ -84,4 +84,4 @@
84 ]
85 }
86 }
87 -}
87 +}
\ No newline at end of file
integrations/schemas/cloud_notification.json new
+68
@@ -0,0 +1,68 @@
1 +{
2 + "$schema": "http://json-schema.org/draft-07/schema#",
3 + "title": "Netdata notification mechanism metadata.",
4 + "oneOf": [
5 + {
6 + "$ref": "#/$defs/entry"
7 + },
8 + {
9 + "type": "array",
10 + "minLength": 1,
11 + "items": {
12 + "$ref": "#/$defs/entry"
13 + }
14 + }
15 + ],
16 + "$defs": {
17 + "entry": {
18 + "type": "object",
19 + "description": "Data for a single notification method.",
20 + "properties": {
21 + "id": {
22 + "$ref": "./shared.json#/$defs/id"
23 + },
24 + "meta": {
25 + "$ref": "./shared.json#/$defs/instance"
26 + },
27 + "keywords": {
28 + "$ref": "./shared.json#/$defs/keywords"
29 + },
30 + "global_setup": {
31 + "type": "object",
32 + "description": "Flags that show which global setup sections are relevant for this notification method.",
33 + "properties": {
34 + "severity_filtering": {
35 + "type": "boolean"
36 + },
37 + "http_proxy": {
38 + "type": "boolean"
39 + }
40 + },
41 + "required": [
42 + "severity_filtering",
43 + "http_proxy"
44 + ]
45 + },
46 + "setup": {
47 + "oneOf": [
48 + {
49 + "$ref": "./shared.json#/$defs/short_setup"
50 + },
51 + {
52 + "$ref": "./shared.json#/$defs/full_setup"
53 + }
54 + ]
55 + },
56 + "troubleshooting": {
57 + "$ref": "./shared.json#/$defs/troubleshooting"
58 + }
59 + },
60 + "required": [
61 + "id",
62 + "meta",
63 + "keywords",
64 + "setup"
65 + ]
66 + }
67 + }
68 +}
\ No newline at end of file
integrations/templates/overview.md
+1 -1
@@ -2,7 +2,7 @@
2 [% include 'overview/collector.md' %]
3 [% elif entry.integration_type == 'exporter' %]
4 [% include 'overview/exporter.md' %]
5 -[% elif entry.integration_type == 'notification' %]
5 +[% elif entry.integration_type == 'agent_notification' %]
6 [% include 'overview/notification.md' %]
7 [% elif entry.integration_type == 'authentication' %]
8 [% include 'overview/authentication.md' %]
integrations/templates/troubleshooting.md
+2 -4
@@ -85,13 +85,12 @@ docker logs netdata 2>&1 | grep [[ entry.meta.module_name ]]
85
86 [% endif %]
87 [% endif %]
88 -[% elif entry.integration_type == 'notification' %]
89 -[% if 'cloud-notifications' in entry._src_path|string %]
88 +[% elif entry.integration_type == 'cloud_notification' %]
89 [% if entry.troubleshooting.problems.list %]
90 ## Troubleshooting
91
92 [% endif %]
94 -[% else %]
93 +[% elif entry.integration_type == 'agent_notification' %]
94 ## Troubleshooting
95
96 ### Test Notification
@@ -114,7 +113,6 @@ export NETDATA_ALARM_NOTIFY_DEBUG=1
113
114 Note that this will test _all_ alert mechanisms for the selected role.
115
117 -[% endif %]
116 [% elif entry.integration_type == 'exporter' %]
117 [% if entry.troubleshooting.problems.list %]
118 ## Troubleshooting