package alertmanager import ( "context" "io" "net/http" "strconv" "time" "github.com/gorilla/mux" "go.signoz.io/signoz/pkg/errors" "go.signoz.io/signoz/pkg/http/render" "go.signoz.io/signoz/pkg/types/alertmanagertypes" "go.signoz.io/signoz/pkg/types/authtypes" ) type API struct { alertmanager Alertmanager } func NewAPI(alertmanager Alertmanager) *API { return &API{ alertmanager: alertmanager, } } func (api *API) GetAlerts(req *http.Request, rw http.ResponseWriter) { ctx, cancel := context.WithTimeout(req.Context(), 30*time.Second) defer cancel() claims, ok := authtypes.ClaimsFromContext(ctx) if !ok { render.Error(rw, errors.Newf(errors.TypeUnauthenticated, errors.CodeUnauthenticated, "unauthenticated")) return } params, err := alertmanagertypes.NewGettableAlertsParams(req) if err != nil { render.Error(rw, err) return } alerts, err := api.alertmanager.GetAlerts(ctx, claims.OrgID, params) if err != nil { render.Error(rw, err) return } render.Success(rw, http.StatusOK, alerts) } func (api *API) TestReceiver(req *http.Request, rw http.ResponseWriter) { ctx, cancel := context.WithTimeout(req.Context(), 30*time.Second) defer cancel() claims, ok := authtypes.ClaimsFromContext(ctx) if !ok { render.Error(rw, errors.Newf(errors.TypeUnauthenticated, errors.CodeUnauthenticated, "unauthenticated")) return } body, err := io.ReadAll(req.Body) if err != nil { render.Error(rw, err) return } defer req.Body.Close() //nolint:errcheck receiver, err := alertmanagertypes.NewReceiver(string(body)) if err != nil { render.Error(rw, err) return } err = api.alertmanager.TestReceiver(ctx, claims.OrgID, receiver) if err != nil { render.Error(rw, err) return } render.Success(rw, http.StatusNoContent, nil) } func (api *API) ListChannels(req *http.Request, rw http.ResponseWriter) { ctx, cancel := context.WithTimeout(req.Context(), 30*time.Second) defer cancel() claims, ok := authtypes.ClaimsFromContext(ctx) if !ok { render.Error(rw, errors.Newf(errors.TypeUnauthenticated, errors.CodeUnauthenticated, "unauthenticated")) return } channels, err := api.alertmanager.ListChannels(ctx, claims.OrgID) if err != nil { render.Error(rw, err) return } render.Success(rw, http.StatusOK, channels) } func (api *API) GetChannelByID(req *http.Request, rw http.ResponseWriter) { ctx, cancel := context.WithTimeout(req.Context(), 30*time.Second) defer cancel() claims, ok := authtypes.ClaimsFromContext(ctx) if !ok { render.Error(rw, errors.Newf(errors.TypeUnauthenticated, errors.CodeUnauthenticated, "unauthenticated")) return } vars := mux.Vars(req) if vars == nil { render.Error(rw, errors.Newf(errors.TypeInvalidInput, errors.CodeInvalidInput, "id is required in path")) return } idString, ok := vars["id"] if !ok { render.Error(rw, errors.Newf(errors.TypeInvalidInput, errors.CodeInvalidInput, "id is required in path")) return } id, err := strconv.Atoi(idString) if err != nil { render.Error(rw, errors.Newf(errors.TypeInvalidInput, errors.CodeInvalidInput, "id is not a valid integer")) return } channel, err := api.alertmanager.GetChannelByID(ctx, claims.OrgID, id) if err != nil { render.Error(rw, err) return } render.Success(rw, http.StatusOK, channel) } func (api *API) UpdateChannelByID(req *http.Request, rw http.ResponseWriter) { ctx, cancel := context.WithTimeout(req.Context(), 30*time.Second) defer cancel() claims, ok := authtypes.ClaimsFromContext(ctx) if !ok { render.Error(rw, errors.Newf(errors.TypeUnauthenticated, errors.CodeUnauthenticated, "unauthenticated")) return } body, err := io.ReadAll(req.Body) if err != nil { render.Error(rw, err) return } defer req.Body.Close() //nolint:errcheck receiver, err := alertmanagertypes.NewReceiver(string(body)) if err != nil { render.Error(rw, err) return } err = api.alertmanager.UpdateChannelByReceiver(ctx, claims.OrgID, receiver) if err != nil { render.Error(rw, err) return } render.Success(rw, http.StatusNoContent, nil) } func (api *API) DeleteChannelByID(req *http.Request, rw http.ResponseWriter) { ctx, cancel := context.WithTimeout(req.Context(), 30*time.Second) defer cancel() claims, ok := authtypes.ClaimsFromContext(ctx) if !ok { render.Error(rw, errors.Newf(errors.TypeUnauthenticated, errors.CodeUnauthenticated, "unauthenticated")) return } vars := mux.Vars(req) if vars == nil { render.Error(rw, errors.Newf(errors.TypeInvalidInput, errors.CodeInvalidInput, "id is required in path")) return } idString, ok := vars["id"] if !ok { render.Error(rw, errors.Newf(errors.TypeInvalidInput, errors.CodeInvalidInput, "id is required in path")) return } id, err := strconv.Atoi(idString) if err != nil { render.Error(rw, errors.Newf(errors.TypeInvalidInput, errors.CodeInvalidInput, "id is not a valid integer")) return } err = api.alertmanager.DeleteChannelByID(ctx, claims.OrgID, id) if err != nil { render.Error(rw, err) return } render.Success(rw, http.StatusNoContent, nil) } func (api *API) CreateChannel(req *http.Request, rw http.ResponseWriter) { ctx, cancel := context.WithTimeout(req.Context(), 30*time.Second) defer cancel() claims, ok := authtypes.ClaimsFromContext(ctx) if !ok { render.Error(rw, errors.Newf(errors.TypeUnauthenticated, errors.CodeUnauthenticated, "unauthenticated")) return } body, err := io.ReadAll(req.Body) if err != nil { render.Error(rw, err) return } defer req.Body.Close() //nolint:errcheck receiver, err := alertmanagertypes.NewReceiver(string(body)) if err != nil { render.Error(rw, err) return } err = api.alertmanager.CreateChannel(ctx, claims.OrgID, receiver) if err != nil { render.Error(rw, err) return } render.Success(rw, http.StatusNoContent, nil) }