@@ -2,9 +2,12 @@ package monitor
22
33import (
44 "context"
5+ "encoding/json"
56 "fmt"
67 "io"
8+ "log"
79 "net/http"
10+ "sync"
811)
912
1013func (c * sysdigMonitorClient ) alertsV2URL () string {
@@ -15,21 +18,71 @@ func (c *sysdigMonitorClient) alertV2URL(alertID int) string {
1518 return fmt .Sprintf ("%s/api/v2/alerts/%d" , c .URL , alertID )
1619}
1720
21+ func (c * sysdigMonitorClient ) labelsDescriptorsV3URL (label string ) string {
22+ return fmt .Sprintf ("%s/api/v3/labels/descriptors/%s" , c .URL , label )
23+ }
24+
25+ func (c * sysdigMonitorClient ) labelsV3URL () string {
26+ return fmt .Sprintf ("%s/api/v3/labels/?limit=6000" , c .URL ) //6000 is the maximum number of labels a customer can have
27+ }
28+
29+ func (c * sysdigMonitorClient ) addNotificationChannelType (ctx context.Context , notificationChannelConfigList []NotificationChannelConfigV2 ) error {
30+ // on put/posts the api wants the type of the channel even if it can be inferred
31+ for i , n := range notificationChannelConfigList {
32+ nc , err := c .GetNotificationChannelById (ctx , n .ChannelID )
33+ if err != nil {
34+ return fmt .Errorf ("error getting info for notification channel %d: %w" , n .ChannelID , err )
35+ }
36+ notificationChannelConfigList [i ].Type = nc .Type
37+ }
38+ return nil
39+ }
40+
41+ func (c * sysdigMonitorClient ) translateScopeSegmentLabels (ctx context.Context , scopedSegmentedConfig * ScopedSegmentedConfig ) error {
42+ // the operand of the scope must be in dot notation
43+ if scopedSegmentedConfig .Scope != nil {
44+ for i , e := range scopedSegmentedConfig .Scope .Expressions {
45+ labelDescriptorV3 , err := c .GetLabelDescriptor (ctx , e .Operand )
46+ if err != nil {
47+ return fmt .Errorf ("error getting descriptor for label %s: %w" , e .Operand , err )
48+ }
49+ scopedSegmentedConfig .Scope .Expressions [i ].Operand = labelDescriptorV3 .ID
50+ }
51+ }
52+
53+ // the label descriptor id must be in dot notation
54+ for i , d := range scopedSegmentedConfig .SegmentBy {
55+ labelDescriptorV3 , err := c .GetLabelDescriptor (ctx , d .ID )
56+ if err != nil {
57+ return fmt .Errorf ("error getting descriptor for label %s: %w" , d .ID , err )
58+ }
59+ scopedSegmentedConfig .SegmentBy [i ].ID = labelDescriptorV3 .ID
60+ }
61+
62+ return nil
63+ }
64+
65+ // prometheus
66+
1867func (c * sysdigMonitorClient ) CreateAlertV2Prometheus (ctx context.Context , alert AlertV2Prometheus ) (createdAlert AlertV2Prometheus , err error ) {
68+ if err = c .addNotificationChannelType (ctx , alert .NotificationChannelConfigList ); err != nil {
69+ return
70+ }
71+
1972 body , err := c .createAlertV2 (ctx , alert .ToJSON ())
2073 if err != nil {
2174 return
2275 }
23- createdAlert = AlertV2PrometheusFromJSON (body )
2476
25- // this fixes the APIs bug of not setting the default group on the response of the create method
26- if createdAlert .Group == "" {
27- createdAlert .Group = "default"
28- }
77+ createdAlert = AlertV2PrometheusFromJSON (body )
2978 return
3079}
3180
3281func (c * sysdigMonitorClient ) UpdateAlertV2Prometheus (ctx context.Context , alert AlertV2Prometheus ) (updatedAlert AlertV2Prometheus , err error ) {
82+ if err = c .addNotificationChannelType (ctx , alert .NotificationChannelConfigList ); err != nil {
83+ return
84+ }
85+
3386 body , err := c .updateAlertV2 (ctx , alert .ID , alert .ToJSON ())
3487 if err != nil {
3588 return
@@ -53,10 +106,166 @@ func (c *sysdigMonitorClient) DeleteAlertV2Prometheus(ctx context.Context, alert
53106 return c .deleteAlertV2 (ctx , alertID )
54107}
55108
109+ // event
110+
111+ func (c * sysdigMonitorClient ) CreateAlertV2Event (ctx context.Context , alert AlertV2Event ) (createdAlert AlertV2Event , err error ) {
112+ if err = c .addNotificationChannelType (ctx , alert .NotificationChannelConfigList ); err != nil {
113+ return
114+ }
115+
116+ if err = c .translateScopeSegmentLabels (ctx , & alert .Config .ScopedSegmentedConfig ); err != nil {
117+ return
118+ }
119+
120+ body , err := c .createAlertV2 (ctx , alert .ToJSON ())
121+ if err != nil {
122+ return
123+ }
124+
125+ createdAlert = AlertV2EventFromJSON (body )
126+ return
127+ }
128+
129+ func (c * sysdigMonitorClient ) UpdateAlertV2Event (ctx context.Context , alert AlertV2Event ) (updatedAlert AlertV2Event , err error ) {
130+ if err = c .addNotificationChannelType (ctx , alert .NotificationChannelConfigList ); err != nil {
131+ return
132+ }
133+
134+ if err = c .translateScopeSegmentLabels (ctx , & alert .Config .ScopedSegmentedConfig ); err != nil {
135+ return
136+ }
137+
138+ body , err := c .updateAlertV2 (ctx , alert .ID , alert .ToJSON ())
139+ if err != nil {
140+ return
141+ }
142+
143+ updatedAlert = AlertV2EventFromJSON (body )
144+ return
145+ }
146+
147+ func (c * sysdigMonitorClient ) GetAlertV2EventById (ctx context.Context , alertID int ) (alert AlertV2Event , err error ) {
148+ body , err := c .getAlertV2ById (ctx , alertID )
149+ if err != nil {
150+ return
151+ }
152+
153+ alert = AlertV2EventFromJSON (body )
154+ return
155+ }
156+
157+ func (c * sysdigMonitorClient ) DeleteAlertV2Event (ctx context.Context , alertID int ) (err error ) {
158+ return c .deleteAlertV2 (ctx , alertID )
159+ }
160+
161+ // metric
162+
163+ func (c * sysdigMonitorClient ) CreateAlertV2Metric (ctx context.Context , alert AlertV2Metric ) (createdAlert AlertV2Metric , err error ) {
164+ if err = c .addNotificationChannelType (ctx , alert .NotificationChannelConfigList ); err != nil {
165+ return
166+ }
167+
168+ if err = c .translateScopeSegmentLabels (ctx , & alert .Config .ScopedSegmentedConfig ); err != nil {
169+ return
170+ }
171+
172+ body , err := c .createAlertV2 (ctx , alert .ToJSON ())
173+ if err != nil {
174+ return
175+ }
176+
177+ createdAlert = AlertV2MetricFromJSON (body )
178+ return
179+ }
180+
181+ func (c * sysdigMonitorClient ) UpdateAlertV2Metric (ctx context.Context , alert AlertV2Metric ) (updatedAlert AlertV2Metric , err error ) {
182+ if err = c .addNotificationChannelType (ctx , alert .NotificationChannelConfigList ); err != nil {
183+ return
184+ }
185+
186+ if err = c .translateScopeSegmentLabels (ctx , & alert .Config .ScopedSegmentedConfig ); err != nil {
187+ return
188+ }
189+
190+ body , err := c .updateAlertV2 (ctx , alert .ID , alert .ToJSON ())
191+ if err != nil {
192+ return
193+ }
194+
195+ updatedAlert = AlertV2MetricFromJSON (body )
196+ return
197+ }
198+
199+ func (c * sysdigMonitorClient ) GetAlertV2MetricById (ctx context.Context , alertID int ) (alert AlertV2Metric , err error ) {
200+ body , err := c .getAlertV2ById (ctx , alertID )
201+ if err != nil {
202+ return
203+ }
204+
205+ alert = AlertV2MetricFromJSON (body )
206+ return
207+ }
208+
209+ func (c * sysdigMonitorClient ) DeleteAlertV2Metric (ctx context.Context , alertID int ) (err error ) {
210+ return c .deleteAlertV2 (ctx , alertID )
211+ }
212+
213+ // downtime
214+
215+ func (c * sysdigMonitorClient ) CreateAlertV2Downtime (ctx context.Context , alert AlertV2Downtime ) (createdAlert AlertV2Downtime , err error ) {
216+ if err = c .addNotificationChannelType (ctx , alert .NotificationChannelConfigList ); err != nil {
217+ return
218+ }
219+
220+ if err = c .translateScopeSegmentLabels (ctx , & alert .Config .ScopedSegmentedConfig ); err != nil {
221+ return
222+ }
223+
224+ body , err := c .createAlertV2 (ctx , alert .ToJSON ())
225+ if err != nil {
226+ return
227+ }
228+
229+ createdAlert = AlertV2DowntimeFromJSON (body )
230+ return
231+ }
232+
233+ func (c * sysdigMonitorClient ) UpdateAlertV2Downtime (ctx context.Context , alert AlertV2Downtime ) (updatedAlert AlertV2Downtime , err error ) {
234+ if err = c .addNotificationChannelType (ctx , alert .NotificationChannelConfigList ); err != nil {
235+ return
236+ }
237+
238+ if err = c .translateScopeSegmentLabels (ctx , & alert .Config .ScopedSegmentedConfig ); err != nil {
239+ return
240+ }
241+
242+ body , err := c .updateAlertV2 (ctx , alert .ID , alert .ToJSON ())
243+ if err != nil {
244+ return
245+ }
246+
247+ updatedAlert = AlertV2DowntimeFromJSON (body )
248+ return
249+ }
250+
251+ func (c * sysdigMonitorClient ) GetAlertV2DowntimeById (ctx context.Context , alertID int ) (alert AlertV2Downtime , err error ) {
252+ body , err := c .getAlertV2ById (ctx , alertID )
253+ if err != nil {
254+ return
255+ }
256+
257+ alert = AlertV2DowntimeFromJSON (body )
258+ return
259+ }
260+
261+ func (c * sysdigMonitorClient ) DeleteAlertV2Downtime (ctx context.Context , alertID int ) (err error ) {
262+ return c .deleteAlertV2 (ctx , alertID )
263+ }
264+
56265// helpers
57266
58267func (c * sysdigMonitorClient ) createAlertV2 (ctx context.Context , alertJson io.Reader ) (responseBody []byte , err error ) {
59- response , err := c .doSysdigMonitorRequest (ctx , http .MethodPost , fmt . Sprintf ( "%s/create" , c .alertsV2URL () ), alertJson )
268+ response , err := c .doSysdigMonitorRequest (ctx , http .MethodPost , c .alertsV2URL (), alertJson )
60269 if err != nil {
61270 return
62271 }
@@ -116,3 +325,99 @@ func (c *sysdigMonitorClient) getAlertV2ById(ctx context.Context, alertID int) (
116325 body , err := io .ReadAll (response .Body )
117326 return body , err
118327}
328+
329+ // buildLabelDescriptor gets the descriptor of a label in public notation from the v3/labels/descriptors api
330+ // this is not a general solution to get the descriptor for a public notation label since custom labels will not be properly translated
331+ // e.g. the public notation cloud_provider_tag_k8s_io_role_master will not be translated to the correct cloudProvider.tag.k8s.io/role/master id
332+ func (c * sysdigMonitorClient ) buildLabelDescriptor (ctx context.Context , label string ) (LabelDescriptorV3 , error ) {
333+ // always returns 200, even if the label does not exist for the customer
334+ response , err := c .doSysdigMonitorRequest (ctx , http .MethodGet , c .labelsDescriptorsV3URL (label ), nil )
335+ if err != nil {
336+ return LabelDescriptorV3 {}, err
337+ }
338+ defer response .Body .Close ()
339+
340+ if response .StatusCode != http .StatusOK {
341+ err = errorFromResponse (response )
342+ return LabelDescriptorV3 {}, err
343+ }
344+
345+ body , err := io .ReadAll (response .Body )
346+ if err != nil {
347+ return LabelDescriptorV3 {}, err
348+ }
349+
350+ var labelsDescriptorsV3result struct {
351+ LabelDescriptorV3 `json:"labelDescriptor"`
352+ }
353+
354+ err = json .Unmarshal (body , & labelsDescriptorsV3result )
355+ if err != nil {
356+ return LabelDescriptorV3 {}, err
357+ }
358+
359+ return labelsDescriptorsV3result .LabelDescriptorV3 , nil
360+ }
361+
362+ func (c * sysdigMonitorClient ) getLabels (ctx context.Context , label string ) ([]LabelDescriptorV3 , error ) {
363+
364+ var labelsResp struct {
365+ AllLabels []LabelDescriptorV3 `json:"allLabels"`
366+ }
367+
368+ response , err := c .doSysdigMonitorRequest (ctx , http .MethodGet , c .labelsV3URL (), nil )
369+ if err != nil {
370+ return nil , err
371+ }
372+ defer response .Body .Close ()
373+
374+ if response .StatusCode != http .StatusOK {
375+ err = errorFromResponse (response )
376+ return nil , err
377+ }
378+
379+ body , err := io .ReadAll (response .Body )
380+ if err != nil {
381+ return nil , err
382+ }
383+
384+ err = json .Unmarshal (body , & labelsResp )
385+ return labelsResp .AllLabels , err
386+
387+ }
388+
389+ var labelCache struct {
390+ sync.Mutex
391+
392+ labels []LabelDescriptorV3
393+ }
394+
395+ // GetLabel gets the descriptor from a label in public notation
396+ func (c * sysdigMonitorClient ) GetLabelDescriptor (ctx context.Context , label string ) (LabelDescriptorV3 , error ) {
397+ var alertDescriptior LabelDescriptorV3
398+
399+ labelCache .Lock ()
400+ defer labelCache .Unlock ()
401+
402+ if len (labelCache .labels ) == 0 {
403+ log .Printf ("[DEBUG] GetLabel for %s: fetching all labels" , label )
404+ labelDescriptors , err := c .getLabels (ctx , label )
405+ if err != nil {
406+ return alertDescriptior , err
407+ }
408+ labelCache .labels = labelDescriptors
409+ } else {
410+ log .Printf ("[DEBUG] GetLabel for %s: using cached labels" , label )
411+ }
412+
413+ for _ , l := range labelCache .labels {
414+ if l .PublicID == label {
415+ return l , nil
416+ }
417+ }
418+
419+ // if the label did not exist, build the descriptor from /v3/labels/descriptor
420+ log .Printf ("[DEBUG] GetLabel for %s: not found in existing customer labels" , label )
421+ return c .buildLabelDescriptor (ctx , label )
422+
423+ }
0 commit comments