44import opsgenie_sdk
55
66from robusta .core .reporting .base import Enrichment , Finding , FindingSeverity
7+ from robusta .core .sinks .common .channel_transformer import ChannelTransformer
78from robusta .core .sinks .opsgenie .opsgenie_sink_params import OpsGenieSinkConfigWrapper
89from robusta .core .sinks .sink_base import SinkBase
910from robusta .core .sinks .transformer import Transformer
@@ -22,9 +23,18 @@ def __init__(self, sink_config: OpsGenieSinkConfigWrapper, registry):
2223
2324 self .api_key = sink_config .opsgenie_sink .api_key
2425 self .teams = sink_config .opsgenie_sink .teams
26+ self .default_team = sink_config .opsgenie_sink .default_team
2527 self .tags = sink_config .opsgenie_sink .tags
2628 self .extra_details_labels = sink_config .opsgenie_sink .extra_details_labels
2729
30+ # Check for dangerous configuration
31+ has_templates = any ("$" in team for team in self .teams )
32+ if has_templates and not self .default_team :
33+ logging .warning (
34+ "OpsGenie sink is configured with templated team names but no default_team specified. "
35+ "Alerts may fail to route if the required label or annotation is missing."
36+ )
37+
2838 opsgenie_sdk .configuration .Configuration .set_default (None )
2939 self .conf = opsgenie_sdk .configuration .Configuration ()
3040 self .conf .api_key ["Authorization" ] = self .api_key
@@ -73,17 +83,48 @@ def __ack_alert(self, fingerprint: str, user: str, note: str):
7383 except opsgenie_sdk .ApiException as err :
7484 logging .error (f"Error acking opsGenie alert { fingerprint } { err } " , exc_info = True )
7585
86+ def __get_teams (self , finding : Finding ) -> List [str ]:
87+ teams = []
88+ for team_template in self .teams :
89+ try :
90+ if "$" in team_template :
91+ # Only process templates that contain variables
92+ team = ChannelTransformer .template (
93+ team_template ,
94+ self .default_team , # Use default_team as fallback
95+ self .cluster_name ,
96+ finding .subject .labels ,
97+ finding .subject .annotations ,
98+ )
99+ if team : # Only add non-null teams
100+ teams .append (team )
101+ else :
102+ # Use static team name directly
103+ teams .append (team_template )
104+ except Exception as e :
105+ logging .warning (
106+ f"Failed to process team template { team_template } for alert subject { finding .service_key } : { e } "
107+ )
108+ continue
109+ return teams
110+
76111 def __open_alert (self , finding : Finding , platform_enabled : bool ):
77112 description = self .__to_description (finding , platform_enabled )
78113 details = self .__to_details (finding )
79114 tags = self .tags .copy ()
80115 tags .insert (0 , self .cluster_name )
116+
117+ # Get teams based on templates
118+ teams = self .__get_teams (finding )
119+ if not teams and self .teams : # dynamic routing failed and no default team configured
120+ logging .warning (f"No valid teams resolved for finding { finding .title } . Alert may not be routed properly." )
121+
81122 body = opsgenie_sdk .CreateAlertPayload (
82123 source = "Robusta" ,
83124 message = finding .title ,
84125 description = description ,
85126 alias = finding .fingerprint ,
86- responders = [{"name" : team , "type" : "team" } for team in self . teams ],
127+ responders = [{"name" : team , "type" : "team" } for team in teams ],
87128 details = details ,
88129 tags = tags ,
89130 entity = finding .service_key ,
0 commit comments