@@ -37,7 +37,7 @@ def date_end_of_day(dt):
3737 return dt .replace (hour = 23 , minute = 59 , second = 59 )
3838
3939
40- def ui_group_url (ui_endpoint , report , timestamp , grouptype , group , environment ):
40+ def ui_group_url (ui_endpoint , report , timestamp , grouptype , group , environment , ui_path_group ):
4141 """Generate an http url to a relevant argo web ui endpoint group timeline page
4242
4343 Args:
@@ -54,10 +54,10 @@ def ui_group_url(ui_endpoint, report, timestamp, grouptype, group, environment)
5454 start_date = date_only_string (date_days_ago (parse_timestamp (timestamp ), 3 ))
5555 end_date = date_only_string (parse_timestamp (timestamp ))
5656 return "https://{0}/{1}/report-status/{2}/{3}/{4}?start={5}&end={6}" .format (
57- ui_endpoint , environment .lower (), report , grouptype . upper () + "S" , group , start_date , end_date )
57+ ui_endpoint , environment .lower (), report , ui_path_group , group , start_date , end_date )
5858
5959
60- def ui_endpoint_url (ui_endpoint , report , timestamp , grouptype , group , service , hostname , environment ):
60+ def ui_endpoint_url (ui_endpoint , report , timestamp , grouptype , group , service , hostname , environment , ui_path_group ):
6161 """Generate an http url to a relevant argo web ui endpoint timeline page
6262
6363 Args:
@@ -76,10 +76,10 @@ def ui_endpoint_url(ui_endpoint, report, timestamp, grouptype, group, service, h
7676 start_date = date_only_string (date_days_ago (parse_timestamp (timestamp ), 3 ))
7777 end_date = date_only_string (parse_timestamp (timestamp ))
7878 return "http://{0}/{1}/report-status/{2}/{3}/{4}/{5}/{6}?start={7}&end={8}" .format (
79- ui_endpoint , environment .lower (), report , grouptype . upper () + "S" , group , service , hostname , start_date , end_date )
79+ ui_endpoint , environment .lower (), report , ui_path_group , group , service , hostname , start_date , end_date )
8080
8181
82- def transform (argo_event , environment , grouptype , timeout , ui_endpoint , report ):
82+ def transform (argo_event , environment , grouptype , timeout , ui_endpoint , report , endpoint_type , ui_path_group ):
8383 """Transform an argo status event to an alerta alert
8484
8585 Args:
@@ -181,7 +181,7 @@ def transform(argo_event, environment, grouptype, timeout, ui_endpoint, report):
181181 environment .upper (), grouptype .capitalize (), group , status .upper ())
182182 if ui_endpoint != "" :
183183 attributes ["_alert_url" ] = ui_group_url (
184- ui_endpoint , report , ts_monitored , grouptype , group , environment )
184+ ui_endpoint , report , ts_monitored , grouptype , group , environment , ui_path_group )
185185
186186 elif etype == "service" :
187187 alerta_service .append ("service" )
@@ -192,11 +192,11 @@ def transform(argo_event, environment, grouptype, timeout, ui_endpoint, report):
192192 elif etype == "endpoint" :
193193 alerta_service .append ("endpoint" )
194194 resource = service + "/" + hostname
195- text = "[ {0} ] - Endpoint {1}/ {2} is {3}" .format (
196- environment .upper (), hostname , service , status .upper ())
195+ text = "[ {0} ] - {4} {1} ( {2}) is {3}" .format (
196+ environment .upper (), hostname , service , status .upper (), endpoint_type . capitalize ())
197197 if ui_endpoint != "" :
198198 attributes ["_alert_url" ] = ui_endpoint_url (
199- ui_endpoint , report , ts_monitored , grouptype , group , service , hostname , environment )
199+ ui_endpoint , report , ts_monitored , grouptype , group , service , hostname , environment , ui_path_group )
200200
201201 elif etype == "metric" :
202202 alerta_service .append ("metric" )
@@ -235,7 +235,7 @@ def read_and_send(message, environment, alerta_url, alerta_token, options):
235235
236236 try :
237237 alerta = transform (argo_event , environment ,
238- options ["group_type" ], options ["timeout" ], options ["ui_endpoint" ], options ["report" ])
238+ options ["group_type" ], options ["timeout" ], options ["ui_endpoint" ], options ["report" ], options [ "endpoint_type" ], options [ "ui_path_group" ] )
239239 except KeyError as e :
240240 logging .warning ("WRONG JSON SCHEMA: " + message .value )
241241 return
@@ -341,26 +341,53 @@ def gocdb_to_contacts(gocdb_xml, use_notif_flag, test_emails):
341341 name = name_tags [0 ].firstChild .nodeValue
342342 service = service_tags [0 ].firstChild .nodeValue
343343 c ["name" ] = "\\ /" + service + "\\ /" + name
344-
344+
345345 if test_emails is None :
346346 c ["emails" ] = item .firstChild .nodeValue
347347 else :
348348 c ["emails" ] = test_emails [indx % len (test_emails )]
349349 c ["original_email" ] = item .firstChild .nodeValue
350350 indx = indx + 1
351-
351+
352352 contacts .append (c )
353353
354354 return contacts
355355
356356
357+ def gen_endpoint_contacts_from_groups (group_data , endpoint_data , group_filter = None ):
358+ """Parse both endpoint and group topology data and refactor endpoint data using
359+ notification information from groups
360+
361+ Args:
362+ endpoint_data (obj): list of endpoint topology data
363+ group_data (string): list of group topology data
364+ group_filter (string): keep only groups of a specific type e.g. SITES
365+
366+ Returns:
367+ obj: list containing endpoint topology data with notification detailes borrowed from groups
368+ """
369+ group_index = {}
370+ gen_endpoints = []
371+ for item in group_data :
372+ group_index [item ["subgroup" ]] = item ["notifications" ]
373+
374+ for item in endpoint_data :
375+ endpoint_group = item ["group" ]
376+ if group_filter and group_filter != item ["type" ]:
377+ # skip endpoint if we have enabled a group filter and its group type doesn't match
378+ continue
379+ if endpoint_group in group_index :
380+ item ["notifications" ] = group_index [endpoint_group ]
381+ gen_endpoints .append (item )
382+
383+ return gen_endpoints
357384
358385def argo_web_api_to_contacts (endpoint_data , group_data , use_notif = False , test_emails = None ):
359386 """Contact argo-web-api endpoint and retrieve contacts for topology endpoints and groups
360387
361388 Args:
362- api_endpoint (string ): endpoint for argo-web-api instance
363- access_key (string): argo-web-api access key
389+ endpoint_data (obj ): list of endpoint topology data
390+ grou_data (string): list of group topology data
364391 verify (bool, optional): Set https verification on/off. Defaults to True.
365392 test_emails (string, optional): Set test emails for notifications. Defaults to None
366393
@@ -371,40 +398,61 @@ def argo_web_api_to_contacts(endpoint_data, group_data, use_notif=False, test_em
371398 get_notif_always = not use_notif
372399
373400
374-
401+
375402 contacts = []
376403 subgroup_types = {}
377404 # iterate over endpoints but also get subgroup types
378405 for indx , endpoint in enumerate (endpoint_data ):
379406 subgroup_types [endpoint ["group" ]]= endpoint ["type" ]
380407 if "notifications" in endpoint :
381- if get_notif_always or (endpoint ["notifications" ]["enabled" ] == True ):
382- name = "{}\\ /{}" .format (endpoint ["service" ].replace ("." ,"\\ ." ),endpoint ["hostname" ].replace ("." ,"\\ ." ))
408+ # if notifications is empty
409+ if get_notif_always or ("enabled" in endpoint ["notifications" ] and endpoint ["notifications" ]["enabled" ] == True ):
410+ name = "{}\\ /{}" .format (endpoint ["service" ].replace ("." ,"\\ ." ), endpoint ["hostname" ].replace ("." ,"\\ ." ))
411+ contact = ""
383412 if not test_emails :
384- contact = ";" .join (endpoint ["notifications" ]["contacts" ])
413+ if "contacts" in endpoint ["notifications" ]:
414+ contact = ";" .join (endpoint ["notifications" ]["contacts" ])
385415 else :
386- contact = test_emails [indx % len (test_emails )]
387- contacts .append ({"name" :name , "emails" :contact , "type" :endpoint ["type" ]})
416+ contact = test_emails [indx % len (test_emails )]
417+ if contact != "" :
418+ contacts .append ({"name" : name , "emails" : contact , "type" : "endpoint" })
419+
420+ # consolidate rules with duplicate names (same endpoint belonging to multiple groups)
421+ contact_index = {}
422+ for contact in contacts :
423+ if contact ["name" ] in contact_index :
424+ # append emails to existing contact rule
425+ contact_index [contact ["name" ]]["emails" ] = contact_index [contact ["name" ]]["emails" ] + ";" + contact ["emails" ]
426+ else :
427+ contact_index [contact ["name" ]] = contact
428+
429+ contacts = list (contact_index .values ())
430+
388431 # iterate now over group data
389432 for indx , group in enumerate (group_data ):
390433 if "notifications" not in group :
391434 continue
392- if get_notif_always or (group ["notifications" ]["enabled" ] == True ):
435+
436+ if get_notif_always or ("enabled" in group ["notifications" ] and group ["notifications" ]["enabled" ] == True ):
393437 name = group ["subgroup" ]
394438 if name not in subgroup_types :
395439 continue
396440 subgroup_type = subgroup_types [name ]
441+ contact = ""
397442 if not test_emails :
398- contact = ";" .join (endpoint ["notifications" ]["contacts" ])
443+ if "contacts" in group ["notifications" ]:
444+ contact = ";" .join (group ["notifications" ]["contacts" ])
399445 else :
400446 contact = test_emails [indx % len (test_emails )]
401- contacts .append ({"name" :name , "emails" :contact , "type" :subgroup_type })
447+ if contact != "" :
448+ contacts .append ({"name" :name , "emails" :contact , "type" :subgroup_type })
449+
402450 return contacts
403451
404452
405453def get_argo_web_api_data (api_endpoint , access_key , verify = True , topology_type = "endpoints" ):
406454 # get endpoint topology
407-
455+
408456 api_url = api_endpoint
409457 if topology_type == "endpoints" :
410458 api_url = api_url + "/api/v2/topology/endpoints"
@@ -414,7 +462,7 @@ def get_argo_web_api_data(api_endpoint, access_key, verify=True, topology_type="
414462 logging .info ("Requesting topology of {} from argo-web-api: {}" .format (topology_type ,api_url ))
415463 r = requests .get (api_url , headers = {
416464 'x-api-key' : access_key , 'Accept' : 'application/json' }, verify = verify )
417-
465+
418466 if r .status_code == 200 :
419467 logging .info ("Argo-web-api topology data retrieved successfully" )
420468 return json .loads (r .text )["data" ]
@@ -480,15 +528,15 @@ def contacts_to_alerta(contacts, extras=None, environment=None):
480528 rule_fields .append (
481529 {"field" : "environment" , "regex" : "{0}" .format (environment )})
482530 rule_contacts = re .split (";|," , c ["emails" ].replace (" " , "" ))
483-
531+
484532 if extras :
485533 rule_contacts .extend (extras )
486534 rule_exclude = True
487535
488536 rule = {"name" : rule_name , "fields" : rule_fields ,
489537 "contacts" : rule_contacts , "exclude" : rule_exclude }
490-
491-
538+
539+
492540
493541 # Check if contacts have original emails -- used during testing
494542 if "original_email" in c :
@@ -536,10 +584,6 @@ def get_gocdb(api_url, auth_info, ca_bundle):
536584
537585 return ""
538586
539-
540-
541-
542-
543587def write_rules (rules , outfile ):
544588 """Writes alerta email rules to a specific output file
545589
@@ -551,4 +595,4 @@ def write_rules(rules, outfile):
551595 json_str = json .dumps (rules , indent = 4 )
552596 logging .info ("Saving rule to file: " + outfile )
553597 with open (outfile , "w" ) as output_file :
554- output_file .write (json_str )
598+ output_file .write (json_str )
0 commit comments