(feature): API - Implement receiver/channel test functionality (#993)

* (feature): Added test receiver/channel functionality
This commit is contained in:
Amol Umbark 2022-04-22 12:11:19 +05:30 committed by GitHub
parent 3c2173de9e
commit 508c6ced80
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 75 additions and 14 deletions

View File

@ -39,6 +39,7 @@ type APIHandler struct {
basePath string
apiPrefix string
reader *Reader
alertManager am.Manager
relationalDB *interfaces.ModelDao
ready func(http.HandlerFunc) http.HandlerFunc
}
@ -46,9 +47,11 @@ type APIHandler struct {
// NewAPIHandler returns an APIHandler
func NewAPIHandler(reader *Reader, relationalDB *interfaces.ModelDao) (*APIHandler, error) {
alertManager := am.New("")
aH := &APIHandler{
reader: reader,
relationalDB: relationalDB,
alertManager: alertManager,
}
aH.ready = aH.testReady
@ -172,6 +175,7 @@ func (aH *APIHandler) RegisterRoutes(router *mux.Router) {
router.HandleFunc("/api/v1/channels/{id}", aH.editChannel).Methods(http.MethodPut)
router.HandleFunc("/api/v1/channels/{id}", aH.deleteChannel).Methods(http.MethodDelete)
router.HandleFunc("/api/v1/channels", aH.createChannel).Methods(http.MethodPost)
router.HandleFunc("/api/v1/testChannel", aH.testChannel).Methods(http.MethodPost)
router.HandleFunc("/api/v1/rules", aH.listRulesFromProm).Methods(http.MethodGet)
router.HandleFunc("/api/v1/rules/{id}", aH.getRule).Methods(http.MethodGet)
router.HandleFunc("/api/v1/rules", aH.createRule).Methods(http.MethodPost)
@ -451,6 +455,33 @@ func (aH *APIHandler) listChannels(w http.ResponseWriter, r *http.Request) {
aH.respond(w, channels)
}
// testChannels sends test alert to all registered channels
func (aH *APIHandler) testChannel(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close()
body, err := ioutil.ReadAll(r.Body)
if err != nil {
zap.S().Errorf("Error in getting req body of testChannel API\n", err)
aH.respondError(w, &model.ApiError{Typ: model.ErrorBadData, Err: err}, nil)
return
}
receiver := &am.Receiver{}
if err := json.Unmarshal(body, receiver); err != nil { // Parse []byte to go struct pointer
zap.S().Errorf("Error in parsing req body of testChannel API\n", err)
aH.respondError(w, &model.ApiError{Typ: model.ErrorBadData, Err: err}, nil)
return
}
// send alert
apiErrorObj := aH.alertManager.TestReceiver(receiver)
if apiErrorObj != nil {
aH.respondError(w, apiErrorObj, nil)
return
}
aH.respond(w, "test alert sent")
}
func (aH *APIHandler) editChannel(w http.ResponseWriter, r *http.Request) {
id := mux.Vars(r)["id"]

View File

@ -2,13 +2,14 @@ package alertManager
// Wrapper to connect and process alert manager functions
import (
"fmt"
"encoding/json"
"bytes"
"encoding/json"
"fmt"
"net/http"
"go.uber.org/zap"
"go.signoz.io/query-service/constants"
"go.signoz.io/query-service/model"
"go.uber.org/zap"
)
const contentType = "application/json"
@ -17,16 +18,17 @@ type Manager interface {
AddRoute(receiver *Receiver) *model.ApiError
EditRoute(receiver *Receiver) *model.ApiError
DeleteRoute(name string) *model.ApiError
TestReceiver(receiver *Receiver) *model.ApiError
}
func New(url string) Manager{
if url == ""{
func New(url string) Manager {
if url == "" {
url = constants.GetAlertManagerApiPrefix()
}
return &manager {
url: url,
return &manager{
url: url,
}
}
@ -34,11 +36,10 @@ type manager struct {
url string
}
func prepareAmChannelApiURL() string {
basePath := constants.GetAlertManagerApiPrefix()
AmChannelApiPath := constants.AmChannelApiPath
if len(AmChannelApiPath) > 0 && rune(AmChannelApiPath[0]) == rune('/') {
AmChannelApiPath = AmChannelApiPath[1:]
}
@ -46,13 +47,18 @@ func prepareAmChannelApiURL() string {
return fmt.Sprintf("%s%s", basePath, AmChannelApiPath)
}
func (m *manager) AddRoute(receiver *Receiver) (*model.ApiError) {
func prepareTestApiURL() string {
basePath := constants.GetAlertManagerApiPrefix()
return fmt.Sprintf("%s%s", basePath, "v1/testReceiver")
}
func (m *manager) AddRoute(receiver *Receiver) *model.ApiError {
receiverString, _ := json.Marshal(receiver)
amURL := prepareAmChannelApiURL()
response, err := http.Post(amURL, contentType, bytes.NewBuffer(receiverString))
if err != nil {
zap.S().Errorf(fmt.Sprintf("Error in getting response of API call to alertmanager(POST %s)\n", amURL), err)
return &model.ApiError{Typ: model.ErrorInternal, Err: err}
@ -81,7 +87,7 @@ func (m *manager) EditRoute(receiver *Receiver) *model.ApiError {
client := &http.Client{}
response, err := client.Do(req)
if err != nil {
zap.S().Errorf(fmt.Sprintf("Error in getting response of API call to alertmanager(PUT %s)\n", amURL), err)
return &model.ApiError{Typ: model.ErrorInternal, Err: err}
@ -125,5 +131,29 @@ func (m *manager) DeleteRoute(name string) *model.ApiError {
return nil
}
func (m *manager) TestReceiver(receiver *Receiver) *model.ApiError {
receiverBytes, _ := json.Marshal(receiver)
amTestURL := prepareTestApiURL()
response, err := http.Post(amTestURL, contentType, bytes.NewBuffer(receiverBytes))
if err != nil {
zap.S().Errorf(fmt.Sprintf("Error in getting response of API call to alertmanager(POST %s)\n", amTestURL), err)
return &model.ApiError{Typ: model.ErrorInternal, Err: err}
}
if response.StatusCode > 201 && response.StatusCode < 400 {
err := fmt.Errorf(fmt.Sprintf("Invalid parameters in test alert api for alertmanager(POST %s)\n", amTestURL), response.Status)
zap.S().Error(err)
return &model.ApiError{Typ: model.ErrorInternal, Err: err}
}
if response.StatusCode > 400 {
err := fmt.Errorf(fmt.Sprintf("Received Server Error response for API call to alertmanager(POST %s)\n", amTestURL), response.Status)
zap.S().Error(err)
return &model.ApiError{Typ: model.ErrorInternal, Err: err}
}
return nil
}