diff --git a/api/init.go b/api/init.go
index 489279ed..16db7fa8 100644
--- a/api/init.go
+++ b/api/init.go
@@ -43,6 +43,27 @@ func Init(cfg *config.AppConfig) {
ui.HandleUIMethod(api.POST, "/elasticsearch/:id/alerting/_aliases", alerting.GetAliases)
ui.HandleUIMethod(api.POST, "/elasticsearch/:id/alerting/_mappings", alerting.GetMappings)
ui.HandleUIMethod(api.GET, "/elasticsearch/:id/alerting/_plugins", alerting.GetPlugins)
+ ui.HandleUIMethod(api.GET, "/elasticsearch/:id/alerting/monitors/:monitorID", alerting.GetMonitor)
+ ui.HandleUIMethod(api.PUT, "/elasticsearch/:id/alerting/monitors/:monitorID", alerting.UpdateMonitor)
+ ui.HandleUIMethod(api.GET, "/elasticsearch/:id/alerting/monitors", alerting.GetMonitors)
+ ui.HandleUIMethod(api.POST, "/elasticsearch/:id/alerting/monitors", alerting.CreateMonitor)
+ ui.HandleUIMethod(api.POST, "/elasticsearch/:id/alerting/monitors/_execute", alerting.ExecuteMonitor)
+ ui.HandleUIMethod(api.DELETE, "/elasticsearch/:id/alerting/monitors/:monitorID", alerting.DeleteMonitor)
+ ui.HandleUIMethod(api.GET, "/elasticsearch/:id/alerting/_settings", alerting.GetSettings)
+ ui.HandleUIMethod(api.GET, "/elasticsearch/:id/alerting/destinations", alerting.GetDestinations)
+ ui.HandleUIMethod(api.POST, "/elasticsearch/:id/alerting/destinations", alerting.CreateDestination)
+ ui.HandleUIMethod(api.PUT, "/elasticsearch/:id/alerting/destinations/:destinationId", alerting.UpdateDestination)
+ ui.HandleUIMethod(api.DELETE, "/elasticsearch/:id/alerting/destinations/:destinationId", alerting.DeleteDestination)
+ ui.HandleUIMethod(api.POST, "/elasticsearch/:id/alerting/destinations/email_accounts", alerting.CreateEmailAccount)
+ ui.HandleUIMethod(api.GET, "/elasticsearch/:id/alerting/destinations/email_accounts", alerting.GetEmailAccounts)
+ ui.HandleUIMethod(api.DELETE, "/elasticsearch/:id/alerting/email_accounts/:emailAccountId", alerting.DeleteEmailAccount)
+ ui.HandleUIMethod(api.GET, "/elasticsearch/:id/alerting/email_accounts/:emailAccountId", alerting.GetEmailAccount)
+ ui.HandleUIMethod(api.PUT, "/elasticsearch/:id/alerting/email_accounts/:emailAccountId", alerting.UpdateEmailAccount)
+ ui.HandleUIMethod(api.POST, "/elasticsearch/:id/alerting/destinations/email_groups", alerting.CreateEmailGroup)
+ ui.HandleUIMethod(api.GET, "/elasticsearch/:id/alerting/destinations/email_groups", alerting.GetEmailGroups)
+ ui.HandleUIMethod(api.DELETE, "/elasticsearch/:id/alerting/email_groups/:emailGroupId", alerting.DeleteEmailGroup)
+ ui.HandleUIMethod(api.PUT, "/elasticsearch/:id/alerting/email_groups/:emailGroupId", alerting.UpdateEmailGroup)
+
task.RegisterScheduleTask(task.ScheduleTask{
diff --git a/service/alerting/alert.go b/service/alerting/alert.go
index 5bb55523..966fd58b 100644
--- a/service/alerting/alert.go
+++ b/service/alerting/alert.go
@@ -34,7 +34,7 @@ func GetAlerts (w http.ResponseWriter, req *http.Request, ps httprouter.Params){
var (
from = getQueryParam(req, "from", "0")
size = getQueryParam(req, "size", "20")
- search = getQueryParam(req, "search")
+ search = getQueryParam(req, "search", "")
sortDirection = getQueryParam(req, "sortDirection", "desc")
sortField = getQueryParam(req, "sortField", "start_time")
severityLevel = getQueryParam(req, "severityLevel", "ALL")
@@ -74,57 +74,65 @@ func GetAlerts (w http.ResponseWriter, req *http.Request, ps httprouter.Params){
clearSearch = strings.Join(searches, "* *")
params["searchString"] = fmt.Sprintf("*%s*", clearSearch)
}
- reqUrl := conf.Endpoint + "/_opendistro/_alerting/monitors/alerts"
+ reqUrl := fmt.Sprintf("%s/%s/_alerting/monitors/alerts", conf.Endpoint, API_PREFIX )
res, err := doRequest(reqUrl, http.MethodGet, params, nil)
if err != nil {
writeError(w, err)
return
}
- var alertRes = AlertResponse{}
+ var alertRes = IfaceMap{}
err = decodeJSON(res.Body, &alertRes)
defer res.Body.Close()
if err != nil {
writeError(w, err)
return
}
+ alerts := []IfaceMap{}
+ rawAlerts := queryValue(alertRes, "alerts", nil)
+ if ds, ok := rawAlerts.([]interface{}); ok {
+ for _, alert := range ds {
+ if alertItem, ok := alert.(map[string]interface{}); ok {
- var alerts = []IfaceMap{}
- for _, hit := range alertRes.Alerts {
- alert := IfaceMap{
- "id": hit["alert_id"],
+ alertItem["version"] = queryValue(alertItem, "alert_version", "")
+ alertItem["id"] = queryValue(alertItem, "alert_id", "")
+ alerts = append(alerts, alertItem)
+ }
}
- for k, v := range hit {
- alert[k] = v
- }
- alert["version"] = hit["alert_version"]
}
writeJSON(w, IfaceMap{
"ok": true,
"alerts": alerts,
- "totalAlerts": alertRes.TotalAlerts,
+ "totalAlerts": queryValue(alertRes, "totalAlerts", 0),
}, http.StatusOK)
}
func writeError(w http.ResponseWriter, err error) {
writeJSON(w, map[string]interface{}{
- "body": map[string]interface{}{
- "ok": false,
- "err": err.Error(),
- },
+ "ok": false,
+ "resp": err.Error(),
}, http.StatusOK)
}
type IfaceMap map[string]interface{}
-type AlertResponse struct {
- Alerts []IfaceMap `json:"alerts"`
- TotalAlerts int `json:"totalAlerts"`
-}
-
func decodeJSON(reader io.Reader, obj interface{}) error{
dec := json.NewDecoder(reader)
- return dec.Decode(obj)
+ err := dec.Decode(obj)
+ if err != nil {
+ return err
+ }
+
+ if m, ok := obj.(*IfaceMap); ok {
+ if errStr := queryValue(*m,"error", nil); errStr != nil {
+ if str, ok := errStr.(string); ok {
+ errors.New(str)
+ }
+ buf, _ := json.Marshal(errStr)
+ return errors.New(string(buf))
+ }
+ }
+ return nil
}
func writeJSON(w http.ResponseWriter, data interface{}, statusCode int){
@@ -168,5 +176,36 @@ func doRequest(requestUrl string, method string, params map[string]string, body
}
req, _ = http.NewRequest(method, requestUrl, reader)
req.Header.Set("content-type", "application/json")
+ req.Header.Set("User-Agent", "Kibana")
return alertClient.Do(req)
+}
+
+func queryValue(obj map[string]interface{}, key string, defaultValue interface{}) interface{} {
+ if key == "" {
+ return obj
+ }
+ idx := strings.Index(key, ".")
+ if idx == -1 {
+ if v, ok := obj[key]; ok {
+ return v
+ }
+ return defaultValue
+ }
+ ckey := key[0:idx]
+
+ if v, ok := obj[ckey]; ok {
+ if vmap, ok := v.(map[string]interface{}); ok {
+ return queryValue(vmap, key[idx+1:], defaultValue)
+ }
+ }
+ return defaultValue
+}
+
+func assignTo(dst IfaceMap, src IfaceMap){
+ if dst == nil || src == nil {
+ return
+ }
+ for k, v := range src {
+ dst[k] = v
+ }
}
\ No newline at end of file
diff --git a/service/alerting/constants.go b/service/alerting/constants.go
new file mode 100644
index 00000000..da9fca8a
--- /dev/null
+++ b/service/alerting/constants.go
@@ -0,0 +1,10 @@
+package alerting
+
+const INFINI_PREFIX = "opendistro"
+
+const PLUGIN_NAME = INFINI_PREFIX + "-alerting"
+const INDEX_PREFIX = INFINI_PREFIX +"-alerting"
+
+const INDEX_ALL_ALERTS = "."+INDEX_PREFIX +`-alert*`
+
+const API_PREFIX = "_opendistro"
\ No newline at end of file
diff --git a/service/alerting/destination.go b/service/alerting/destination.go
new file mode 100644
index 00000000..815fdc2d
--- /dev/null
+++ b/service/alerting/destination.go
@@ -0,0 +1,720 @@
+package alerting
+
+import (
+ "errors"
+ "fmt"
+ httprouter "infini.sh/framework/core/api/router"
+ "infini.sh/framework/core/elastic"
+ "net/http"
+ "strings"
+)
+
+func GetDestination(w http.ResponseWriter, req *http.Request, ps httprouter.Params) {
+ id := ps.ByName("id")
+ conf := elastic.GetConfig(id)
+ if conf == nil {
+ writeError(w, errors.New("cluster not found"))
+ return
+ }
+
+ dstID := ps.ByName("destID")
+ reqUrl := fmt.Sprintf("%s/_opendistro/_alerting/monitors/%s", conf.Endpoint, dstID)
+ res, err := doRequest(reqUrl, http.MethodGet, nil, nil)
+ if err != nil {
+ writeError(w, err)
+ return
+ }
+ var resBody = IfaceMap{}
+ err = decodeJSON(res.Body, &resBody)
+ if err != nil {
+ writeError(w, err)
+ return
+ }
+ res.Body.Close()
+
+ if _, ok := resBody["monitor"]; !ok {
+ writeJSON(w, IfaceMap{
+ "ok": false,
+ }, http.StatusOK)
+ return
+ }
+
+ queryDSL := ` {
+ "size": 0,
+ "query"": {
+ "bool": {
+ "must": {
+ "term"": {
+ "monitor_id": "%s",
+ },
+ },
+ },
+ },
+ "aggs": {
+ "active_count": {
+ "terms": {
+ "field": "state",
+ }
+ },
+ "24_hour_count": {
+ "date_range": {
+ "field": "start_time",
+ "ranges": [{ "from": "now-24h/h" }]
+ }
+ }
+ }
+ }`
+ queryDSL = fmt.Sprintf(queryDSL, id)
+ reqUrl = fmt.Sprintf("%s/_opendistro/_alerting/monitors/_search", conf.Endpoint)
+ res, err = doRequest(reqUrl, http.MethodPost, map[string]string{
+ "index": ".opendistro-alerting-alert*",
+ }, queryDSL)
+
+ if err != nil {
+ writeError(w, err)
+ return
+ }
+
+ var searchResBody = IfaceMap{}
+ err = decodeJSON(res.Body, &searchResBody)
+ if err != nil {
+ writeError(w, err)
+ return
+ }
+ dayCount := queryValue(searchResBody, "aggregations.24_hour_count.buckets.0.doc_count", 0)
+ activeBuckets := queryValue(searchResBody, "aggregations.active_count.buckets",[]interface{}{})
+ activeCount := 0
+ if ab, ok := activeBuckets.([]IfaceMap); ok {
+ for _, curr := range ab {
+ if curr["key"].(string) == "ACTIVE" {
+ activeCount = int(curr["doc_count"].(float64))
+ }
+ }
+ }
+ writeJSON(w, IfaceMap{
+ "ok": true,
+ "resp": resBody["monitor"],
+ "activeCount": activeCount,
+ "dayCount": dayCount,
+ "version": queryValue(resBody, "_version", nil),
+ "ifSeqNo": queryValue(resBody, "_seq_no", nil),
+ "ifPrimaryTerm": queryValue(resBody, "_primary_term", nil),
+ }, http.StatusOK)
+}
+
+func GetDestinations(w http.ResponseWriter, req *http.Request, ps httprouter.Params) {
+ id := ps.ByName("id")
+ conf := elastic.GetConfig(id)
+ if conf == nil {
+ writeError(w, errors.New("cluster not found"))
+ return
+ }
+ var (
+ from = getQueryParam(req, "from", "0")
+ size = getQueryParam(req, "size", "20")
+ search = getQueryParam(req, "search", "")
+ sortDirection = getQueryParam(req, "sortDirection", "desc")
+ sortField = getQueryParam(req, "sortField", "start_time")
+ typ = getQueryParam(req, "type", "ALL")
+ )
+
+ var params = map[string]string{}
+ switch (sortField) {
+ case "name":
+ params = map[string]string{
+ "sortString": "destination.name.keyword",
+ "sortOrder": sortDirection,
+ }
+ case "type":
+ params = map[string]string{
+ "sortString": "destination.type",
+ "sortOrder": sortDirection,
+ }
+ default:
+ }
+ params["startIndex"] = from
+ params["size"] = size
+ params["searchString"] = search
+ params["destinationType"] = typ
+ if clearSearch := strings.TrimSpace(search); clearSearch != "" {
+ clearSearch = strings.ReplaceAll(clearSearch, " ", "* *")
+ params["searchString"] = clearSearch
+ }
+
+ reqUrl := fmt.Sprintf("%s/%s/_alerting/destinations", conf.Endpoint, API_PREFIX)
+ res, err := doRequest(reqUrl, http.MethodGet, params, nil)
+
+ if err != nil {
+ writeError(w, err)
+ return
+ }
+
+ var resBody = IfaceMap{}
+ err = decodeJSON(res.Body, &resBody)
+ if err != nil {
+ writeError(w, err)
+ return
+ }
+ rawDests := queryValue(resBody, "destinations", []interface{}{})
+ dests := []IfaceMap{}
+
+ if ds, ok := rawDests.([]interface{}); ok {
+ for _, dest := range ds {
+ if destination, ok := dest.(map[string]interface{}); ok {
+
+ destination["version"] = queryValue(destination, "schema_version", "")
+ destination["ifSeqNo"] = queryValue(destination, "seq_no", 0)
+ destination["ifPrimaryTerm"] = queryValue(destination, "primary_term", 0)
+ dests = append(dests, destination)
+ }
+ }
+ }
+ writeJSON(w, IfaceMap{
+ "ok": true,
+ "destinations": dests,
+ "totalDestinations": queryValue(resBody, "totalDestinations", 0),
+ }, http.StatusOK)
+}
+
+func CreateDestination(w http.ResponseWriter, req *http.Request, ps httprouter.Params) {
+ id := ps.ByName("id")
+ conf := elastic.GetConfig(id)
+ if conf == nil {
+ writeError(w, errors.New("cluster not found"))
+ return
+ }
+
+ reqUrl := fmt.Sprintf("%s/%s/_alerting/destinations", conf.Endpoint, API_PREFIX)
+ res, err := doRequest(reqUrl, http.MethodPost, map[string]string{
+ "refresh": "wait_for",
+ }, req.Body)
+ if err != nil {
+ writeError(w, err)
+ return
+ }
+
+ var resBody = IfaceMap{}
+ err = decodeJSON(res.Body, &resBody)
+ res.Body.Close()
+ if err != nil {
+ writeError(w, err)
+ return
+ }
+
+ writeJSON(w, IfaceMap{
+ "ok": true,
+ "resp": resBody,
+ }, http.StatusOK)
+
+}
+
+func UpdateDestination(w http.ResponseWriter, req *http.Request, ps httprouter.Params) {
+ id := ps.ByName("id")
+ conf := elastic.GetConfig(id)
+ if conf == nil {
+ writeError(w, errors.New("cluster not found"))
+ return
+ }
+
+ destinationId := ps.ByName("destinationId")
+ var (
+ ifSeqNo = getQueryParam(req, "ifSeqNo")
+ ifPrimaryTerm = getQueryParam(req, "ifPrimaryTerm")
+ )
+ //PUT /_opendistro/_alerting/destinations/2g3CsHsB3EDgQAwRGzgS?if_seq_no=15&if_primary_term=2&refresh=wait_for
+
+ reqUrl := fmt.Sprintf("%s/%s/_alerting/destinations/%s", conf.Endpoint, API_PREFIX, destinationId)
+ res, err := doRequest(reqUrl, http.MethodPut, map[string]string{
+ "refresh": "wait_for",
+ "if_seq_no": ifSeqNo,
+ "if_primary_term": ifPrimaryTerm,
+ }, req.Body)
+ if err != nil {
+ writeError(w, err)
+ return
+ }
+
+ var resBody = IfaceMap{}
+ err = decodeJSON(res.Body, &resBody)
+ res.Body.Close()
+ if err != nil {
+ writeError(w, err)
+ return
+ }
+ //TODO error handle: check whether resBody has contains field error
+
+ writeJSON(w, IfaceMap{
+ "ok": true,
+ "version": queryValue(resBody, "_version", ""),
+ "id": queryValue(resBody, "_id", ""),
+ }, http.StatusOK)
+
+}
+
+func DeleteDestination(w http.ResponseWriter, req *http.Request, ps httprouter.Params) {
+ id := ps.ByName("id")
+ conf := elastic.GetConfig(id)
+ if conf == nil {
+ writeError(w, errors.New("cluster not found"))
+ return
+ }
+
+ destinationId := ps.ByName("destinationId")
+
+ reqUrl := fmt.Sprintf("%s/%s/_alerting/destinations/%s", conf.Endpoint, API_PREFIX, destinationId)
+ res, err := doRequest(reqUrl, http.MethodDelete, nil, nil)
+ if err != nil {
+ writeError(w, err)
+ return
+ }
+
+ var resBody = IfaceMap{}
+ err = decodeJSON(res.Body, &resBody)
+ res.Body.Close()
+ if err != nil {
+ writeError(w, err)
+ return
+ }
+ //TODO error handle: check whether resBody has contains field error
+
+ resultIfce := queryValue(resBody, "result", "")
+ var isOk = false
+ if result, ok := resultIfce.(string); ok && result == "deleted" {
+ isOk = true
+ }
+ writeJSON(w, IfaceMap{
+ "ok": isOk,
+ }, http.StatusOK)
+
+}
+
+func CreateEmailAccount(w http.ResponseWriter, req *http.Request, ps httprouter.Params) {
+ id := ps.ByName("id")
+ conf := elastic.GetConfig(id)
+ if conf == nil {
+ writeError(w, errors.New("cluster not found"))
+ return
+ }
+
+ reqUrl := fmt.Sprintf("%s/%s/_alerting/destinations/email_accounts", conf.Endpoint, API_PREFIX)
+ res, err := doRequest(reqUrl, http.MethodPost, map[string]string{
+ "refresh": "wait_for",
+ }, req.Body)
+ if err != nil {
+ writeError(w, err)
+ return
+ }
+
+ var resBody = IfaceMap{}
+ err = decodeJSON(res.Body, &resBody)
+ res.Body.Close()
+ if err != nil {
+ writeError(w, err)
+ return
+ }
+
+ writeJSON(w, IfaceMap{
+ "ok": true,
+ "resp": resBody,
+ }, http.StatusOK)
+}
+
+func UpdateEmailAccount(w http.ResponseWriter, req *http.Request, ps httprouter.Params) {
+ id := ps.ByName("id")
+ conf := elastic.GetConfig(id)
+ if conf == nil {
+ writeError(w, errors.New("cluster not found"))
+ return
+ }
+
+ emailAccountId := ps.ByName("emailAccountId")
+ var (
+ ifSeqNo = getQueryParam(req, "ifSeqNo")
+ ifPrimaryTerm = getQueryParam(req, "ifPrimaryTerm")
+ )
+
+ reqUrl := fmt.Sprintf("%s/%s/_alerting/destinations/email_accounts/%s", conf.Endpoint, API_PREFIX, emailAccountId)
+ res, err := doRequest(reqUrl, http.MethodPut, map[string]string{
+ "refresh": "wait_for",
+ "if_seq_no": ifSeqNo,
+ "if_primary_term": ifPrimaryTerm,
+ }, req.Body)
+ if err != nil {
+ writeError(w, err)
+ return
+ }
+
+ var resBody = IfaceMap{}
+ err = decodeJSON(res.Body, &resBody)
+ res.Body.Close()
+ if err != nil {
+ writeError(w, err)
+ return
+ }
+ //TODO error handle: check whether resBody has contains field error
+
+ writeJSON(w, IfaceMap{
+ "ok": true,
+ "id": queryValue(resBody, "_id", ""),
+ }, http.StatusOK)
+
+}
+
+func DeleteEmailAccount(w http.ResponseWriter, req *http.Request, ps httprouter.Params) {
+ id := ps.ByName("id")
+ conf := elastic.GetConfig(id)
+ if conf == nil {
+ writeError(w, errors.New("cluster not found"))
+ return
+ }
+
+ emailAccountId := ps.ByName("emailAccountId")
+
+ reqUrl := fmt.Sprintf("%s/%s/_alerting/destinations/email_accounts/%s", conf.Endpoint, API_PREFIX, emailAccountId)
+ res, err := doRequest(reqUrl, http.MethodDelete, nil, nil)
+ if err != nil {
+ writeError(w, err)
+ return
+ }
+
+ var resBody = IfaceMap{}
+ err = decodeJSON(res.Body, &resBody)
+ res.Body.Close()
+ if err != nil {
+ writeError(w, err)
+ return
+ }
+ //TODO error handle: check whether resBody has contains field error
+
+ resultIfce := queryValue(resBody, "result", "")
+ var isOk = false
+ if result, ok := resultIfce.(string); ok && result == "deleted" {
+ isOk = true
+ }
+ writeJSON(w, IfaceMap{
+ "ok": isOk,
+ }, http.StatusOK)
+
+}
+
+func GetEmailAccounts(w http.ResponseWriter, req *http.Request, ps httprouter.Params) {
+ id := ps.ByName("id")
+ conf := elastic.GetConfig(id)
+ if conf == nil {
+ writeError(w, errors.New("cluster not found"))
+ return
+ }
+ var (
+ from = getQueryParam(req, "from", "0")
+ size = getQueryParam(req, "size", "20")
+ search = getQueryParam(req, "search", "")
+ sortDirection = getQueryParam(req, "sortDirection", "desc")
+ sortField = getQueryParam(req, "sortField", "name")
+ )
+
+ must := IfaceMap{
+ "match_all": IfaceMap{},
+ }
+
+ if clearSearch := strings.TrimSpace(search); clearSearch != "" {
+ clearSearch = strings.ReplaceAll(clearSearch, " ", "* *")
+ must = IfaceMap{
+ "query_string": IfaceMap{
+ "default_field": "email_account.name",
+ "default_operator": "AND",
+ "query": fmt.Sprintf(`*%s*`, clearSearch),
+ },
+ }
+ }
+
+ sortQueryMap := IfaceMap{ "name": IfaceMap{ "email_account.name.keyword": sortDirection } }
+ var sort interface{}
+ if sortQuery, ok := sortQueryMap[sortField]; ok {
+ sort = sortQuery
+ }
+ reqBody := IfaceMap{
+ "from": from,
+ "size": size,
+ "sort": sort,
+ "query": IfaceMap{
+ "bool": IfaceMap{
+ "must": must,
+ },
+ },
+ }
+
+ reqUrl := fmt.Sprintf("%s/%s/_alerting/destinations/email_accounts/_search", conf.Endpoint, API_PREFIX)
+ res, err := doRequest(reqUrl, http.MethodPost, nil, reqBody)
+ //TODO to handle api error in doRequest function
+ if err != nil {
+ writeError(w, err)
+ return
+ }
+
+ var resBody = IfaceMap{}
+ err = decodeJSON(res.Body, &resBody)
+ if err != nil {
+ writeError(w, err)
+ return
+ }
+ totalEmailAccounts := queryValue(resBody, "hits.total.value", 0)
+ rawHits := queryValue(resBody, "hits.hits", []interface{}{})
+ emailAccounts := []IfaceMap{}
+
+ if rh, ok := rawHits.([]interface{}); ok {
+ for _, hit := range rh {
+ if emailAccount, ok := hit.(map[string]interface{}); ok {
+ newItem := IfaceMap{}
+ newItem["id"] = queryValue(emailAccount, "_id", "")
+ source := queryValue(emailAccount, "_source", nil)
+ if ms, ok := source.(map[string]interface{}); ok {
+ assignTo(newItem, ms)
+ }
+ newItem["ifSeqNo"] = queryValue(emailAccount, "_seq_no", 0)
+ newItem["ifPrimaryTerm"] = queryValue(emailAccount, "_primary_term", 0)
+ emailAccounts = append(emailAccounts, newItem)
+ }
+ }
+ }
+ writeJSON(w, IfaceMap{
+ "ok": true,
+ "emailAccounts": emailAccounts,
+ "totalEmailAccounts": totalEmailAccounts,
+ }, http.StatusOK)
+}
+
+func GetEmailAccount(w http.ResponseWriter, req *http.Request, ps httprouter.Params) {
+ id := ps.ByName("id")
+ conf := elastic.GetConfig(id)
+ if conf == nil {
+ writeError(w, errors.New("cluster not found"))
+ return
+ }
+
+ emailAccountId := ps.ByName("emailAccountId")
+
+ reqUrl := fmt.Sprintf("%s/%s/_alerting/destinations/email_accounts/%s", conf.Endpoint, API_PREFIX, emailAccountId)
+ res, err := doRequest(reqUrl, http.MethodGet,nil, req.Body)
+ if err != nil {
+ writeError(w, err)
+ return
+ }
+
+ var resBody = IfaceMap{}
+ err = decodeJSON(res.Body, &resBody)
+ res.Body.Close()
+ if err != nil {
+ writeError(w, err)
+ return
+ }
+ //TODO error handle: check whether resBody has contains field error
+
+ writeJSON(w, IfaceMap{
+ "ok": true,
+ "resp": queryValue(resBody, "email_account", nil),
+ "ifSeqNo": queryValue(resBody, "_seq_no", 0),
+ "ifPrimaryTerm": queryValue(resBody, "_primary_term", 0),
+ }, http.StatusOK)
+
+}
+
+
+// --- email group
+
+func CreateEmailGroup(w http.ResponseWriter, req *http.Request, ps httprouter.Params) {
+ id := ps.ByName("id")
+ conf := elastic.GetConfig(id)
+ if conf == nil {
+ writeError(w, errors.New("cluster not found"))
+ return
+ }
+
+ reqUrl := fmt.Sprintf("%s/%s/_alerting/destinations/email_groups", conf.Endpoint, API_PREFIX)
+ res, err := doRequest(reqUrl, http.MethodPost, map[string]string{
+ "refresh": "wait_for",
+ }, req.Body)
+ if err != nil {
+ writeError(w, err)
+ return
+ }
+
+ var resBody = IfaceMap{}
+ err = decodeJSON(res.Body, &resBody)
+ res.Body.Close()
+ if err != nil {
+ writeError(w, err)
+ return
+ }
+
+ writeJSON(w, IfaceMap{
+ "ok": true,
+ "resp": resBody,
+ }, http.StatusOK)
+}
+
+func UpdateEmailGroup(w http.ResponseWriter, req *http.Request, ps httprouter.Params) {
+ id := ps.ByName("id")
+ conf := elastic.GetConfig(id)
+ if conf == nil {
+ writeError(w, errors.New("cluster not found"))
+ return
+ }
+
+ emailGroupId := ps.ByName("emailGroupId")
+ var (
+ ifSeqNo = getQueryParam(req, "ifSeqNo")
+ ifPrimaryTerm = getQueryParam(req, "ifPrimaryTerm")
+ )
+
+ reqUrl := fmt.Sprintf("%s/%s/_alerting/destinations/email_groups/%s", conf.Endpoint, API_PREFIX, emailGroupId)
+ res, err := doRequest(reqUrl, http.MethodPut, map[string]string{
+ "refresh": "wait_for",
+ "if_seq_no": ifSeqNo,
+ "if_primary_term": ifPrimaryTerm,
+ }, req.Body)
+ if err != nil {
+ writeError(w, err)
+ return
+ }
+
+ var resBody = IfaceMap{}
+ err = decodeJSON(res.Body, &resBody)
+ res.Body.Close()
+ if err != nil {
+ writeError(w, err)
+ return
+ }
+ //TODO error handle: check whether resBody has contains field error
+
+ writeJSON(w, IfaceMap{
+ "ok": true,
+ "id": queryValue(resBody, "_id", ""),
+ }, http.StatusOK)
+
+}
+
+func DeleteEmailGroup(w http.ResponseWriter, req *http.Request, ps httprouter.Params) {
+ id := ps.ByName("id")
+ conf := elastic.GetConfig(id)
+ if conf == nil {
+ writeError(w, errors.New("cluster not found"))
+ return
+ }
+
+ emailGroupId := ps.ByName("emailGroupId")
+
+ reqUrl := fmt.Sprintf("%s/%s/_alerting/destinations/email_groups/%s", conf.Endpoint, API_PREFIX, emailGroupId)
+ res, err := doRequest(reqUrl, http.MethodDelete, nil, nil)
+ if err != nil {
+ writeError(w, err)
+ return
+ }
+
+ var resBody = IfaceMap{}
+ err = decodeJSON(res.Body, &resBody)
+ res.Body.Close()
+ if err != nil {
+ writeError(w, err)
+ return
+ }
+ //TODO error handle: check whether resBody has contains field error
+
+ resultIfce := queryValue(resBody, "result", "")
+ var isOk = false
+ if result, ok := resultIfce.(string); ok && result == "deleted" {
+ isOk = true
+ }
+ writeJSON(w, IfaceMap{
+ "ok": isOk,
+ }, http.StatusOK)
+
+}
+
+func GetEmailGroups(w http.ResponseWriter, req *http.Request, ps httprouter.Params) {
+ id := ps.ByName("id")
+ conf := elastic.GetConfig(id)
+ if conf == nil {
+ writeError(w, errors.New("cluster not found"))
+ return
+ }
+ var (
+ from = getQueryParam(req, "from", "0")
+ size = getQueryParam(req, "size", "20")
+ search = getQueryParam(req, "search", "")
+ sortDirection = getQueryParam(req, "sortDirection", "desc")
+ sortField = getQueryParam(req, "sortField", "name")
+ )
+
+ must := IfaceMap{
+ "match_all": IfaceMap{},
+ }
+
+ if clearSearch := strings.TrimSpace(search); clearSearch != "" {
+ clearSearch = strings.ReplaceAll(clearSearch, " ", "* *")
+ must = IfaceMap{
+ "query_string": IfaceMap{
+ "default_field": "email_group.name",
+ "default_operator": "AND",
+ "query": fmt.Sprintf(`*%s*`, clearSearch),
+ },
+ }
+ }
+
+ sortQueryMap := IfaceMap{ "name": IfaceMap{ "email_group.name.keyword": sortDirection } }
+ var sort interface{}
+ if sortQuery, ok := sortQueryMap[sortField]; ok {
+ sort = sortQuery
+ }
+ reqBody := IfaceMap{
+ "from": from,
+ "size": size,
+ "sort": sort,
+ "query": IfaceMap{
+ "bool": IfaceMap{
+ "must": must,
+ },
+ },
+ }
+
+ reqUrl := fmt.Sprintf("%s/%s/_alerting/destinations/email_groups/_search", conf.Endpoint, API_PREFIX)
+ res, err := doRequest(reqUrl, http.MethodPost, nil, reqBody)
+ //TODO to handle api error in doRequest function
+ if err != nil {
+ writeError(w, err)
+ return
+ }
+
+ var resBody = IfaceMap{}
+ err = decodeJSON(res.Body, &resBody)
+ if err != nil {
+ writeError(w, err)
+ return
+ }
+ totalEmailGroups := queryValue(resBody, "hits.total.value", 0)
+ rawHits := queryValue(resBody, "hits.hits", []interface{}{})
+ emailGroups := []IfaceMap{}
+
+ if rh, ok := rawHits.([]interface{}); ok {
+ for _, hit := range rh {
+ if emailGroup, ok := hit.(map[string]interface{}); ok {
+ newItem := IfaceMap{}
+ newItem["id"] = queryValue(emailGroup, "_id", "")
+ source := queryValue(emailGroup, "_source", nil)
+ if ms, ok := source.(map[string]interface{}); ok {
+ assignTo(newItem, ms)
+ }
+ newItem["ifSeqNo"] = queryValue(emailGroup, "seq_no", 0)
+ newItem["ifPrimaryTerm"] = queryValue(emailGroup, "primary_term", 0)
+ emailGroups = append(emailGroups, newItem)
+ }
+ }
+ }
+ writeJSON(w, IfaceMap{
+ "ok": true,
+ "emailGroups": emailGroups,
+ "totalEmailGroups": totalEmailGroups,
+ }, http.StatusOK)
+}
+
+
+
diff --git a/service/alerting/elasticsearch.go b/service/alerting/elasticsearch.go
index a1e17d1e..f8b023c6 100644
--- a/service/alerting/elasticsearch.go
+++ b/service/alerting/elasticsearch.go
@@ -7,6 +7,7 @@ import (
"infini.sh/framework/core/elastic"
"net/http"
"runtime/debug"
+ "strings"
)
type SearchBody struct {
@@ -28,7 +29,7 @@ func Search(w http.ResponseWriter, req *http.Request, ps httprouter.Params){
writeError(w, err)
return
}
- reqUrl := conf.Endpoint +"/_opendistro/_alerting/monitors/_search"
+ reqUrl := fmt.Sprintf("%s/%s/_alerting/monitors/_search", conf.Endpoint, API_PREFIX)
params := map[string]string{
"index": body.Index,
}
@@ -47,10 +48,8 @@ func Search(w http.ResponseWriter, req *http.Request, ps httprouter.Params){
}
writeJSON(w, IfaceMap{
- "body": IfaceMap{
- "ok": true,
- "resp": resBody,
- },
+ "ok": true,
+ "resp": resBody,
}, http.StatusOK)
}
@@ -90,10 +89,8 @@ func GetIndices(w http.ResponseWriter, req *http.Request, ps httprouter.Params)
}
writeJSON(w, IfaceMap{
- "body": IfaceMap{
- "ok": true,
- "resp": resBody,
- },
+ "ok": true,
+ "resp": resBody,
}, http.StatusOK)
}
@@ -137,10 +134,8 @@ func GetAliases(w http.ResponseWriter, req *http.Request, ps httprouter.Params)
}
writeJSON(w, IfaceMap{
- "body": IfaceMap{
- "ok": true,
- "resp": resBody,
- },
+ "ok": true,
+ "resp": resBody,
}, http.StatusOK)
}
@@ -153,14 +148,14 @@ func GetMappings(w http.ResponseWriter, req *http.Request, ps httprouter.Params)
}
var body = struct{
- Index string `json:"index"`
+ Index []string `json:"index"`
}{}
err := decodeJSON(req.Body, &body)
if err != nil {
writeError(w, err)
return
}
- reqUrl := fmt.Sprintf("%s/%s/_mapping", conf.Endpoint, body.Index)
+ reqUrl := fmt.Sprintf("%s/%s/_mapping", conf.Endpoint, strings.Join(body.Index, ","))
res, err := doRequest(reqUrl, http.MethodGet, nil, nil)
if err != nil {
writeError(w, err)
@@ -175,10 +170,8 @@ func GetMappings(w http.ResponseWriter, req *http.Request, ps httprouter.Params)
}
writeJSON(w, IfaceMap{
- "body": IfaceMap{
- "ok": true,
- "resp": resBody,
- },
+ "ok": true,
+ "resp": resBody,
}, http.StatusOK)
}
@@ -209,9 +202,38 @@ func GetPlugins(w http.ResponseWriter, req *http.Request, ps httprouter.Params)
}
writeJSON(w, IfaceMap{
- "body": IfaceMap{
- "ok": true,
- "resp": resBody,
- },
+ "ok": true,
+ "resp": resBody,
+ }, http.StatusOK)
+}
+
+func GetSettings(w http.ResponseWriter, req *http.Request, ps httprouter.Params) {
+ id := ps.ByName("id")
+ conf := elastic.GetConfig(id)
+ if conf == nil {
+ writeError(w, errors.New("cluster not found"))
+ return
+ }
+
+ // /_cluster/settings?include_defaults=true
+ reqUrl := fmt.Sprintf("%s/_cluster/settings", conf.Endpoint)
+ res, err := doRequest(reqUrl, http.MethodGet, map[string]string{
+ "include_defaults": "true",
+ }, nil)
+ if err != nil {
+ writeError(w, err)
+ return
+ }
+ defer res.Body.Close()
+ var resBody = IfaceMap{}
+ err = decodeJSON(res.Body, &resBody)
+ if err != nil {
+ writeError(w, err)
+ return
+ }
+
+ writeJSON(w, IfaceMap{
+ "ok": true,
+ "resp": resBody,
}, http.StatusOK)
}
\ No newline at end of file
diff --git a/service/alerting/monitor.go b/service/alerting/monitor.go
index bab92227..929c4801 100644
--- a/service/alerting/monitor.go
+++ b/service/alerting/monitor.go
@@ -6,10 +6,18 @@ import (
httprouter "infini.sh/framework/core/api/router"
"infini.sh/framework/core/elastic"
"net/http"
+ "runtime/debug"
+ "strconv"
"strings"
+ "time"
)
func GetMonitor(w http.ResponseWriter, req *http.Request, ps httprouter.Params) {
+ defer func() {
+ if err := recover(); err != nil {
+ debug.PrintStack()
+ }
+ }()
id := ps.ByName("id")
conf := elastic.GetConfig(id)
if conf == nil {
@@ -19,7 +27,7 @@ func GetMonitor(w http.ResponseWriter, req *http.Request, ps httprouter.Params)
mid := ps.ByName("monitorID")
// /_opendistro/_alerting/monitors/uiSjqXsBHT9Hsiy5Dq6g
- reqUrl := fmt.Sprintf("%s/_opendistro/_alerting/monitors/%s", conf.Endpoint, mid)
+ reqUrl := fmt.Sprintf("%s/%s/_alerting/monitors/%s", conf.Endpoint, API_PREFIX, mid)
res, err := doRequest(reqUrl, http.MethodGet, nil, nil)
if err != nil {
writeError(w, err)
@@ -35,29 +43,26 @@ func GetMonitor(w http.ResponseWriter, req *http.Request, ps httprouter.Params)
if _, ok := resBody["monitor"]; !ok {
writeJSON(w, IfaceMap{
- "body": IfaceMap{
"ok": false,
- },
}, http.StatusOK)
return
}
- ///_opendistro/_alerting/monitors/_search?index=.opendistro-alerting-alert*
queryDSL := ` {
"size": 0,
- "query"": {
+ "query": {
"bool": {
"must": {
- "term"": {
- "monitor_id": "%s",
- },
- },
- },
+ "term": {
+ "monitor_id": "%s"
+ }
+ }
+ }
},
"aggs": {
"active_count": {
"terms": {
- "field": "state",
+ "field": "state"
}
},
"24_hour_count": {
@@ -69,9 +74,9 @@ func GetMonitor(w http.ResponseWriter, req *http.Request, ps httprouter.Params)
}
}`
queryDSL = fmt.Sprintf(queryDSL, id)
- reqUrl = fmt.Sprintf("%s/_opendistro/_alerting/monitors/_search", conf.Endpoint)
+ reqUrl = fmt.Sprintf("%s/%s/_alerting/monitors/_search", conf.Endpoint, API_PREFIX)
res, err = doRequest(reqUrl, http.MethodPost, map[string]string{
- "index": ".opendistro-alerting-alert*",
+ "index": INDEX_ALL_ALERTS,
}, queryDSL)
if err != nil {
@@ -85,34 +90,400 @@ func GetMonitor(w http.ResponseWriter, req *http.Request, ps httprouter.Params)
writeError(w, err)
return
}
- //dayCount := queryValue(searchResBody, "aggregations.24_hour_count.buckets.0.doc_count", 0)
- //activeBuckets := queryValue(searchResBody, "aggregations.active_count.buckets",[]interface{}{})
+ dayCount := queryValue(searchResBody, "aggregations.24_hour_count.buckets.0.doc_count", 0)
+ activeBuckets := queryValue(searchResBody, "aggregations.active_count.buckets",[]interface{}{})
+ activeCount := 0
+ if ab, ok := activeBuckets.([]IfaceMap); ok {
+ for _, curr := range ab {
+ if curr["key"].(string) == "ACTIVE" {
+ activeCount = int(curr["doc_count"].(float64))
+ }
+ }
+ }
writeJSON(w, IfaceMap{
- "body": IfaceMap{
- "ok": true,
- "resp": resBody,
- },
+ "ok": true,
+ "resp": resBody["monitor"],
+ "activeCount": activeCount,
+ "dayCount": dayCount,
+ "version": queryValue(resBody, "_version", nil),
+ "ifSeqNo": queryValue(resBody, "_seq_no", nil),
+ "ifPrimaryTerm": queryValue(resBody, "_primary_term", nil),
}, http.StatusOK)
}
-func queryValue(obj map[string]interface{}, key string, defaultValue interface{}) interface{} {
- if key == "" {
- return obj
- }
- idx := strings.Index(key, ".")
- if idx == -1 {
- if v, ok := obj[key]; ok {
- return v
+func GetMonitors(w http.ResponseWriter, req *http.Request, ps httprouter.Params) {
+ defer func() {
+ if err := recover(); err != nil {
+ debug.PrintStack()
}
- return defaultValue
+ }()
+ id := ps.ByName("id")
+ conf := elastic.GetConfig(id)
+ if conf == nil {
+ writeError(w, errors.New("cluster not found"))
+ return
+ }
+ var (
+ from = getQueryParam(req, "from")
+ size = getQueryParam(req, "size")
+ search = getQueryParam(req, "search")
+ sortDirection = getQueryParam(req, "sortDirection")
+ sortField = getQueryParam(req, "sortField")
+ state = getQueryParam(req, "state")
+ must = IfaceMap{ "match_all": IfaceMap{} }
+ )
+ if clearSearch := strings.TrimSpace(search); clearSearch != "" {
+ clearSearch = strings.ReplaceAll(clearSearch, " ", "* *")
+ must = IfaceMap{
+ "query_string": IfaceMap{
+ "default_field": "monitor.name",
+ "default_operator": "AND",
+ "query": fmt.Sprintf("*%s*", clearSearch),
+ },
+ }
+ }
+ var filter = []IfaceMap{
+ IfaceMap{ "term": IfaceMap{ "monitor.type": "monitor" }},
+ }
+ if state != "all" {
+ filter = append(filter, IfaceMap{
+ "term": IfaceMap{ "monitor.enabled": state == "enabled" },
+ })
+ }
+ var monitorSorts = IfaceMap{ "name": "monitor.name.keyword" }
+ sortPageData := IfaceMap{
+ "size": 1000,
+ "from": 0,
+ }
+ var (
+ intSize int
+ intFrom int
+ )
+ if msort, ok := monitorSorts[sortField]; ok {
+ sortPageData["sort"] = []IfaceMap{
+ { msort.(string): sortDirection },
+ }
+ intSize, _ = strconv.Atoi(size)
+ if intSize < 0 {
+ intSize = 1000
+ }
+ sortPageData["size"] = intSize
+ intFrom, _ = strconv.Atoi(from)
+ if intFrom < 0 {
+ intFrom = 0
+ }
+ sortPageData["from"] = intFrom
+ }
+ var params = IfaceMap{
+ "seq_no_primary_term": true,
+ "version": true,
+ "query": IfaceMap{
+ "bool": IfaceMap{
+ "filter": filter,
+ "must": must,
+ },
+ },
+ }
+ assignTo(params, sortPageData)
+ reqUrl := fmt.Sprintf("%s/%s/_alerting/monitors/_search", conf.Endpoint, API_PREFIX )
+ res, err := doRequest(reqUrl, http.MethodPost, nil, params)
+ if err != nil {
+ writeError(w, err)
+ return
}
- ckey := key[0:idx]
+ var resBody = IfaceMap{}
+ err = decodeJSON(res.Body, &resBody)
+ if err != nil {
+ writeError(w, err)
+ return
+ }
- if v, ok := obj[ckey]; ok {
- if vmap, ok := v.(map[string]interface{}); ok {
- return queryValue(vmap, key[idx+1:], defaultValue)
+ totalMonitors := queryValue(resBody, "hits.total.value", 0)
+ monitorMap:= map[string]IfaceMap{}
+ var hits = queryValue(resBody, "hits.hits", []IfaceMap{})
+ monitorIDs := []interface{}{}
+ if hitsArr, ok := hits.([]interface{}); ok {
+ for _, hitIface := range hitsArr {
+ if hit, ok := hitIface.(map[string]interface{}); ok {
+ id := queryValue(hit, "_id", "")
+ monitorIDs = append(monitorIDs, id)
+ monitor := queryValue(hit, "_source", IfaceMap{}).(map[string]interface{})
+ monitorMap[id.(string)] = IfaceMap{
+ "id": id,
+ "version": queryValue(hit, "_version", ""),
+ "ifSeqNo": queryValue(hit, "_seq_no", false),
+ "ifPrimaryTerm": queryValue(hit, "_primary_term", false),
+ "name": queryValue(monitor, "name", ""),
+ "enabled": queryValue(monitor, "enabled", false),
+ "monitor": monitor,
+ }
+ }
}
}
- return defaultValue
-}
\ No newline at end of file
+
+
+ aggsOrderData := IfaceMap{}
+ aggsSorts := IfaceMap{
+ "active": "active",
+ "acknowledged": "acknowledged",
+ "errors": "errors",
+ "ignored": "ignored",
+ "lastNotificationTime": "last_notification_time",
+ }
+
+ if sortF, ok := aggsSorts[sortField]; ok {
+ aggsOrderData["order"] = IfaceMap{ sortF.(string): sortDirection }
+ }
+ var queryParams = map[string]string{
+ "index": INDEX_ALL_ALERTS,
+ }
+ var termsMap = IfaceMap{
+ "field": "monitor_id",
+ "size": intFrom + intSize,
+ }
+ assignTo(termsMap, aggsOrderData)
+ var aggsParams = IfaceMap{
+ "size": 0,
+ "query": IfaceMap{ "terms": IfaceMap{ "monitor_id": monitorIDs } },
+ "aggregations": IfaceMap{
+ "uniq_monitor_ids": IfaceMap{
+ "terms": termsMap,
+ "aggregations": IfaceMap{
+ "active": IfaceMap{ "filter": IfaceMap{ "term": IfaceMap{ "state": "ACTIVE" } } },
+ "acknowledged": IfaceMap{ "filter": IfaceMap{ "term": IfaceMap{ "state": "ACKNOWLEDGED" } } },
+ "errors": IfaceMap{ "filter": IfaceMap{ "term": IfaceMap{ "state": "ERROR" } } },
+ "ignored": IfaceMap{
+ "filter": IfaceMap{
+ "bool": IfaceMap{
+ "filter": IfaceMap{ "term": IfaceMap{ "state": "COMPLETED" } },
+ "must_not": IfaceMap{ "exists": IfaceMap{ "field": "acknowledged_time" } },
+ },
+ },
+ },
+ "last_notification_time": IfaceMap{ "max": IfaceMap{ "field": "last_notification_time" } },
+ "latest_alert": IfaceMap{
+ "top_hits": IfaceMap{
+ "size": 1,
+ "sort": []IfaceMap{ { "start_time": IfaceMap{ "order": "desc" }} },
+ "_source": IfaceMap{
+ "includes": []string{"last_notification_time", "trigger_name"},
+ },
+ },
+ },
+ },
+ },
+ },
+ }
+
+
+ reqUrl = fmt.Sprintf("%s/%s/_alerting/monitors/_search", conf.Endpoint, API_PREFIX)
+ searchRes, err := doRequest(reqUrl, http.MethodPost, queryParams, aggsParams)
+ if err != nil {
+ writeError(w, err)
+ return
+ }
+
+ var searchResBody = IfaceMap{}
+ err = decodeJSON(searchRes.Body, &searchResBody)
+ if err != nil {
+ writeError(w, err)
+ return
+ }
+ buckets := queryValue(searchResBody, "aggregations.uniq_monitor_ids.buckets",[]IfaceMap{})
+ usedMonitors := []IfaceMap{}
+ if bks, ok := buckets.([]interface{}); ok {
+ for _, bk := range bks {
+ if bk, ok := bk.(map[string]interface{}); ok {
+ id := queryValue(bk, "key", "")
+ monitor := monitorMap[id.(string)]
+ monitor["lastNotificationTime"] = queryValue(bk, "last_notification_time.value", "")
+ monitor["ignored"] = queryValue(bk, "ignored.doc_count", 0)
+ alertHits := queryValue(bk, "latest_alert.hits.hits", nil)
+ var latestAlert interface{}
+ if hits, ok := alertHits.([]interface{}); ok && len(hits) > 0 {
+ if hitMap, ok := hits[0].(map[string]interface{}); ok {
+ latestAlert = queryValue(hitMap, "_source.trigger_name", nil)
+ }
+ }
+ monitor["latestAlert"] = latestAlert
+ monitor["active"] = queryValue(bk, "active.doc_count", 0)
+ monitor["errors"] = queryValue(bk, "errors.doc_count", 0)
+ monitor["currentTime"] = time.Now().UnixNano() / 1e6
+ usedMonitors = append(usedMonitors, monitor)
+ delete(monitorMap, id.(string))
+ }
+ }
+ }
+ unusedMonitors := []IfaceMap{}
+
+ for _, m := range monitorMap {
+ assignTo(m, IfaceMap{
+ "lastNotificationTime": nil,
+ "ignored": 0,
+ "active": 0,
+ "acknowledged": 0,
+ "errors": 0,
+ "latestAlert": "--",
+ "currentTime": time.Now().UnixNano()/1e6,
+ })
+ unusedMonitors = append(unusedMonitors,m)
+ }
+
+ results := append(usedMonitors, unusedMonitors...)
+
+ if _, ok := monitorSorts[sortField]; !ok {
+ results = results[intFrom: intFrom + intSize]
+ }
+ writeJSON(w, IfaceMap{
+ "ok": true,
+ "monitors": results,
+ "totalMonitors": totalMonitors,
+ }, http.StatusOK)
+}
+
+
+func CreateMonitor(w http.ResponseWriter, req *http.Request, ps httprouter.Params) {
+ id := ps.ByName("id")
+ conf := elastic.GetConfig(id)
+ if conf == nil {
+ writeError(w, errors.New("cluster not found"))
+ return
+ }
+
+ reqUrl := fmt.Sprintf("%s/%s/_alerting/monitors", conf.Endpoint, API_PREFIX)
+ res, err := doRequest(reqUrl, http.MethodPost, map[string]string{
+ "refresh": "wait_for",
+ }, req.Body)
+ if err != nil {
+ writeError(w, err)
+ return
+ }
+
+ var resBody = IfaceMap{}
+ err = decodeJSON(res.Body, &resBody)
+ res.Body.Close()
+ if err != nil {
+ writeError(w, err)
+ return
+ }
+
+ writeJSON(w, IfaceMap{
+ "ok": true,
+ "resp": resBody,
+ }, http.StatusOK)
+}
+
+func DeleteMonitor(w http.ResponseWriter, req *http.Request, ps httprouter.Params) {
+ id := ps.ByName("id")
+ conf := elastic.GetConfig(id)
+ if conf == nil {
+ writeError(w, errors.New("cluster not found"))
+ return
+ }
+
+ monitorId := ps.ByName("monitorID")
+
+ reqUrl := fmt.Sprintf("%s/%s/_alerting/monitors/%s", conf.Endpoint, API_PREFIX, monitorId)
+ res, err := doRequest(reqUrl, http.MethodDelete, nil, nil)
+ if err != nil {
+ writeError(w, err)
+ return
+ }
+
+ var resBody = IfaceMap{}
+ err = decodeJSON(res.Body, &resBody)
+ res.Body.Close()
+ if err != nil {
+ writeError(w, err)
+ return
+ }
+ //TODO error handle: check whether resBody has contains field error
+
+ resultIfce := queryValue(resBody, "result", "")
+ var isOk = false
+ if result, ok := resultIfce.(string); ok && result == "deleted" {
+ isOk = true
+ }
+ writeJSON(w, IfaceMap{
+ "ok": isOk,
+ }, http.StatusOK)
+
+}
+
+func UpdateMonitor(w http.ResponseWriter, req *http.Request, ps httprouter.Params) {
+ id := ps.ByName("id")
+ conf := elastic.GetConfig(id)
+ if conf == nil {
+ writeError(w, errors.New("cluster not found"))
+ return
+ }
+
+ monitorId := ps.ByName("monitorID")
+ var (
+ ifSeqNo = getQueryParam(req, "ifSeqNo")
+ ifPrimaryTerm = getQueryParam(req, "ifPrimaryTerm")
+ )
+
+ reqUrl := fmt.Sprintf("%s/%s/_alerting/monitors/%s", conf.Endpoint, API_PREFIX, monitorId)
+ res, err := doRequest(reqUrl, http.MethodPut, map[string]string{
+ "refresh": "wait_for",
+ "if_seq_no": ifSeqNo,
+ "if_primary_term": ifPrimaryTerm,
+ }, req.Body)
+ if err != nil {
+ writeError(w, err)
+ return
+ }
+
+ var resBody = IfaceMap{}
+ err = decodeJSON(res.Body, &resBody)
+ res.Body.Close()
+ if err != nil {
+ writeError(w, err)
+ return
+ }
+ //TODO error handle: check whether resBody has contains field error
+
+ writeJSON(w, IfaceMap{
+ "ok": true,
+ "version": queryValue(resBody, "_version", ""),
+ "id": queryValue(resBody, "_id", ""),
+ }, http.StatusOK)
+
+}
+
+func ExecuteMonitor(w http.ResponseWriter, req *http.Request, ps httprouter.Params) {
+ id := ps.ByName("id")
+ conf := elastic.GetConfig(id)
+ if conf == nil {
+ writeError(w, errors.New("cluster not found"))
+ return
+ }
+ var (
+ dryrun = getQueryParam(req, "dryrun", "true")
+ )
+
+ reqUrl := fmt.Sprintf("%s/%s/_alerting/monitors/_execute", conf.Endpoint, API_PREFIX)
+ res, err := doRequest(reqUrl, http.MethodPost, map[string]string{
+ "dryrun": dryrun,
+ }, req.Body)
+ if err != nil {
+ writeError(w, err)
+ return
+ }
+
+ var resBody = IfaceMap{}
+ err = decodeJSON(res.Body, &resBody)
+ res.Body.Close()
+ if err != nil {
+ writeError(w, err)
+ return
+ }
+ //TODO error handle: check whether resBody has contains field error
+
+ writeJSON(w, IfaceMap{
+ "ok": true,
+ "resp": resBody,
+ }, http.StatusOK)
+}
diff --git a/web/package.json b/web/package.json
index 95a38560..50df795a 100644
--- a/web/package.json
+++ b/web/package.json
@@ -72,7 +72,7 @@
"rxjs": "^7.2.0",
"sass-loader": "^8.0.2",
"use-query-params": "^1.2.3",
- "uuidv4": "^6.2.12"
+ "uuid-v4": "^0.1.0"
},
"devDependencies": {
"antd-pro-merge-less": "^0.1.0",
diff --git a/web/src/pages/Alerting/components/Breadcrumbs/Breadcrumbs.js b/web/src/pages/Alerting/components/Breadcrumbs/Breadcrumbs.js
index fddeca60..18805224 100644
--- a/web/src/pages/Alerting/components/Breadcrumbs/Breadcrumbs.js
+++ b/web/src/pages/Alerting/components/Breadcrumbs/Breadcrumbs.js
@@ -129,7 +129,7 @@ export async function getBreadcrumb(route, routeState, httpClient) {
// TODO::Everything else is considered as monitor, we should break this.
let monitorName = base;
try {
- const response = await httpClient.get(`../api/alerting/monitors/${base}`);
+ const response = await httpClient.get(`/alerting/monitors/${base}`);
if (response.ok) {
monitorName = response.resp.name;
}
diff --git a/web/src/pages/Alerting/index.js b/web/src/pages/Alerting/index.js
index b424c192..cd975389 100644
--- a/web/src/pages/Alerting/index.js
+++ b/web/src/pages/Alerting/index.js
@@ -12,7 +12,7 @@ const httpClient = new Fetch({
get: () => '',
prepend: (url) => url,
remove: (url) => url,
- serverBasePath: '/elasticsearch',
+ serverBasePath: '',
}
});
const notifications = {
@@ -23,6 +23,11 @@ const notifications = {
description: text,
duration: toastLifeTimeMs/1000,
})
+ },
+ addSuccess: (message) => {
+ notification.success({
+ description: message,
+ })
}
}
}
@@ -32,8 +37,8 @@ const AlertingUI = (props)=>{
return null;
}
useMemo(()=>{
- httpClient.getServerBasePath = ()=>{
- return '/api/elasticsearch/'+ props.selectedCluster.id;
+ httpClient.params.basePath.prepend = (url)=>{
+ return '/elasticsearch/'+ props.selectedCluster.id + url;
}
}, [props.selectedCluster]);
const isDarkMode = false;
diff --git a/web/src/pages/Alerting/pages/CreateMonitor/containers/AnomalyDetectors/AnomalyDetectorData.js b/web/src/pages/Alerting/pages/CreateMonitor/containers/AnomalyDetectors/AnomalyDetectorData.js
index 5728f18f..b01a6153 100644
--- a/web/src/pages/Alerting/pages/CreateMonitor/containers/AnomalyDetectors/AnomalyDetectorData.js
+++ b/web/src/pages/Alerting/pages/CreateMonitor/containers/AnomalyDetectors/AnomalyDetectorData.js
@@ -56,7 +56,7 @@ class AnomalyDetectorData extends React.Component {
preview: this.props.preview,
};
try {
- const response = await httpClient.get(`../api/alerting/detectors/${detectorId}/results`, {
+ const response = await httpClient.get(`/alerting/detectors/${detectorId}/results`, {
query: requestParams,
});
if (response.ok) {
diff --git a/web/src/pages/Alerting/pages/CreateMonitor/containers/AnomalyDetectors/AnomalyDetectors.js b/web/src/pages/Alerting/pages/CreateMonitor/containers/AnomalyDetectors/AnomalyDetectors.js
index ef44d5bc..e916c9ac 100644
--- a/web/src/pages/Alerting/pages/CreateMonitor/containers/AnomalyDetectors/AnomalyDetectors.js
+++ b/web/src/pages/Alerting/pages/CreateMonitor/containers/AnomalyDetectors/AnomalyDetectors.js
@@ -38,7 +38,7 @@ class AnomalyDetectors extends React.Component {
async searchDetectors() {
const { http: httpClient, notifications } = this.context;
try {
- const response = await httpClient.post('../api/alerting/detectors/_search');
+ const response = await httpClient.post('/alerting/detectors/_search');
if (response.ok) {
const detectorOptions = response.detectors
.filter((detector) => detector.detectionDateRange === undefined)
diff --git a/web/src/pages/Alerting/pages/CreateMonitor/containers/CreateMonitor/CreateMonitor.js b/web/src/pages/Alerting/pages/CreateMonitor/containers/CreateMonitor/CreateMonitor.js
index 32926c73..61ed24c0 100644
--- a/web/src/pages/Alerting/pages/CreateMonitor/containers/CreateMonitor/CreateMonitor.js
+++ b/web/src/pages/Alerting/pages/CreateMonitor/containers/CreateMonitor/CreateMonitor.js
@@ -76,7 +76,7 @@ export default class CreateMonitor extends Component {
async onCreate(monitor, { setSubmitting, setErrors }) {
const { httpClient, notifications } = this.props;
try {
- const resp = await httpClient.post('../api/alerting/monitors', {
+ const resp = await httpClient.post('/alerting/monitors', {
body: JSON.stringify(monitor),
});
setSubmitting(false);
diff --git a/web/src/pages/Alerting/pages/CreateMonitor/containers/CreateMonitor/CreateMonitor.test.js b/web/src/pages/Alerting/pages/CreateMonitor/containers/CreateMonitor/CreateMonitor.test.js
index a469ef26..fdbf65eb 100644
--- a/web/src/pages/Alerting/pages/CreateMonitor/containers/CreateMonitor/CreateMonitor.test.js
+++ b/web/src/pages/Alerting/pages/CreateMonitor/containers/CreateMonitor/CreateMonitor.test.js
@@ -249,7 +249,7 @@ describe('CreateMonitor', () => {
);
wrapper.instance().onCreate(monitor, formikBag);
expect(httpClientMock.post).toHaveBeenCalledTimes(1);
- expect(httpClientMock.post).toHaveBeenCalledWith('../api/alerting/monitors', {
+ expect(httpClientMock.post).toHaveBeenCalledWith('/alerting/monitors', {
body: JSON.stringify(monitor),
});
});
diff --git a/web/src/pages/Alerting/pages/CreateMonitor/containers/DefineMonitor/DefineMonitor.js b/web/src/pages/Alerting/pages/CreateMonitor/containers/DefineMonitor/DefineMonitor.js
index 70707057..4391d5ff 100644
--- a/web/src/pages/Alerting/pages/CreateMonitor/containers/DefineMonitor/DefineMonitor.js
+++ b/web/src/pages/Alerting/pages/CreateMonitor/containers/DefineMonitor/DefineMonitor.js
@@ -126,7 +126,7 @@ class DefineMonitor extends Component {
async getPlugins() {
const { httpClient } = this.props;
try {
- const pluginsResponse = await httpClient.get('../api/alerting/_plugins');
+ const pluginsResponse = await httpClient.get('/alerting/_plugins');
if (pluginsResponse.ok) {
this.setState({ plugins: pluginsResponse.resp.map((plugin) => plugin.component) });
} else {
@@ -186,7 +186,7 @@ class DefineMonitor extends Component {
_.set(monitor, 'name', 'TEMP_MONITOR');
_.set(monitor, 'triggers', []);
_.set(monitor, 'inputs[0].search', searchRequest);
- return httpClient.post('../api/alerting/monitors/_execute', {
+ return httpClient.post('/alerting/monitors/_execute', {
body: JSON.stringify(monitor),
});
});
@@ -231,7 +231,7 @@ class DefineMonitor extends Component {
}
try {
- const response = await this.props.httpClient.post('../api/alerting/_mappings', {
+ const response = await this.props.httpClient.post('/alerting/_mappings', {
body: JSON.stringify({ index }),
});
if (response.ok) {
diff --git a/web/src/pages/Alerting/pages/CreateMonitor/containers/MonitorIndex/MonitorIndex.js b/web/src/pages/Alerting/pages/CreateMonitor/containers/MonitorIndex/MonitorIndex.js
index d434c700..2291c1fc 100644
--- a/web/src/pages/Alerting/pages/CreateMonitor/containers/MonitorIndex/MonitorIndex.js
+++ b/web/src/pages/Alerting/pages/CreateMonitor/containers/MonitorIndex/MonitorIndex.js
@@ -120,7 +120,7 @@ class MonitorIndex extends React.Component {
return [];
}
try {
- const response = await this.props.httpClient.post('../api/alerting/_indices', {
+ const response = await this.props.httpClient.post('/alerting/_indices', {
body: JSON.stringify({ index }),
});
if (response.ok) {
@@ -150,7 +150,7 @@ class MonitorIndex extends React.Component {
}
try {
- const response = await this.props.httpClient.post('../api/alerting/_aliases', {
+ const response = await this.props.httpClient.post('/alerting/_aliases', {
body: JSON.stringify({ alias }),
});
if (response.ok) {
diff --git a/web/src/pages/Alerting/pages/CreateTrigger/containers/ConfigureActions/ConfigureActions.js b/web/src/pages/Alerting/pages/CreateTrigger/containers/ConfigureActions/ConfigureActions.js
index 627d2892..9e22c4e6 100644
--- a/web/src/pages/Alerting/pages/CreateTrigger/containers/ConfigureActions/ConfigureActions.js
+++ b/web/src/pages/Alerting/pages/CreateTrigger/containers/ConfigureActions/ConfigureActions.js
@@ -62,7 +62,7 @@ class ConfigureActions extends React.Component {
return destination.type;
};
try {
- const response = await httpClient.get('../api/alerting/destinations', {
+ const response = await httpClient.get('/alerting/destinations', {
query: { search: searchText, size: MAX_QUERY_RESULT_SIZE },
});
if (response.ok) {
@@ -97,7 +97,7 @@ class ConfigureActions extends React.Component {
const condition = { script: { lang: 'painless', source: 'return true' } };
const testMonitor = { ...monitor, triggers: [{ ...trigger, actions: [action], condition }] };
try {
- const response = await httpClient.post('../api/alerting/monitors/_execute', {
+ const response = await httpClient.post('/alerting/monitors/_execute', {
query: { dryrun: false },
body: JSON.stringify(testMonitor),
});
diff --git a/web/src/pages/Alerting/pages/CreateTrigger/containers/CreateTrigger/CreateTrigger.js b/web/src/pages/Alerting/pages/CreateTrigger/containers/CreateTrigger/CreateTrigger.js
index ed749cc1..2239ccea 100644
--- a/web/src/pages/Alerting/pages/CreateTrigger/containers/CreateTrigger/CreateTrigger.js
+++ b/web/src/pages/Alerting/pages/CreateTrigger/containers/CreateTrigger/CreateTrigger.js
@@ -128,7 +128,7 @@ export default class CreateTrigger extends Component {
_.set(monitorToExecute, 'inputs[0].search', searchRequest);
}
httpClient
- .post('../api/alerting/monitors/_execute', { body: JSON.stringify(monitorToExecute) })
+ .post('/alerting/monitors/_execute', { body: JSON.stringify(monitorToExecute) })
.then((resp) => {
if (resp.ok) {
this.setState({ executeResponse: resp.resp });
diff --git a/web/src/pages/Alerting/pages/Dashboard/containers/Dashboard.js b/web/src/pages/Alerting/pages/Dashboard/containers/Dashboard.js
index f54f1b31..2978feb0 100644
--- a/web/src/pages/Alerting/pages/Dashboard/containers/Dashboard.js
+++ b/web/src/pages/Alerting/pages/Dashboard/containers/Dashboard.js
@@ -185,7 +185,7 @@ export default class Dashboard extends Component {
location.search;
const { httpClient, history, notifications } = this.props;
history.replace({ ...this.props.location, search: queryParamsString });
- httpClient.get(httpClient.getServerBasePath()+'/alerting/alerts', { query: params }).then((resp) => {
+ httpClient.get('/alerting/alerts', { query: params }).then((resp) => {
if (resp.ok) {
const { alerts, totalAlerts } = resp;
this.setState({
@@ -218,7 +218,7 @@ export default class Dashboard extends Component {
const promises = Object.entries(monitorAlerts).map(([monitorId, alerts]) =>
httpClient
- .post(`../api/alerting/monitors/${monitorId}/_acknowledge/alerts`, {
+ .post(`/alerting/monitors/${monitorId}/_acknowledge/alerts`, {
body: JSON.stringify({ alerts }),
})
.then((resp) => {
diff --git a/web/src/pages/Alerting/pages/Dashboard/utils/tableUtils.js b/web/src/pages/Alerting/pages/Dashboard/utils/tableUtils.js
index cb289adc..e30a615b 100644
--- a/web/src/pages/Alerting/pages/Dashboard/utils/tableUtils.js
+++ b/web/src/pages/Alerting/pages/Dashboard/utils/tableUtils.js
@@ -52,7 +52,7 @@ export const columns = [
truncateText: true,
textOnly: true,
render: (name, alert) => (
- {name}
+ {name}
),
},
{
diff --git a/web/src/pages/Alerting/pages/Destinations/containers/CreateDestination/CreateDestination.js b/web/src/pages/Alerting/pages/Destinations/containers/CreateDestination/CreateDestination.js
index 08e11b2d..42410832 100644
--- a/web/src/pages/Alerting/pages/Destinations/containers/CreateDestination/CreateDestination.js
+++ b/web/src/pages/Alerting/pages/Destinations/containers/CreateDestination/CreateDestination.js
@@ -89,7 +89,7 @@ class CreateDestination extends React.Component {
getDestination = async (destinationId) => {
const { httpClient, history, notifications } = this.props;
try {
- const resp = await httpClient.get(`../api/alerting/destinations/${destinationId}`);
+ const resp = await httpClient.get(`/alerting/destinations/${destinationId}`);
if (resp.ok) {
const ifSeqNo = _.get(resp, 'ifSeqNo');
const ifPrimaryTerm = _.get(resp, 'ifPrimaryTerm');
@@ -118,7 +118,7 @@ class CreateDestination extends React.Component {
} = this.props;
const { ifSeqNo, ifPrimaryTerm } = this.state;
try {
- const resp = await httpClient.put(`../api/alerting/destinations/${destinationId}`, {
+ const resp = await httpClient.put(`/alerting/destinations/${destinationId}`, {
query: { ifSeqNo, ifPrimaryTerm },
body: JSON.stringify(requestData),
});
@@ -139,7 +139,7 @@ class CreateDestination extends React.Component {
handleCreate = async (requestData, { setSubmitting }) => {
const { httpClient, history, notifications } = this.props;
try {
- const resp = await httpClient.post('../api/alerting/destinations', {
+ const resp = await httpClient.post('/alerting/destinations', {
body: JSON.stringify(requestData),
});
setSubmitting(false);
diff --git a/web/src/pages/Alerting/pages/Destinations/containers/CreateDestination/EmailRecipients/utils/helpers.js b/web/src/pages/Alerting/pages/Destinations/containers/CreateDestination/EmailRecipients/utils/helpers.js
index fe64d6f8..12f9a157 100644
--- a/web/src/pages/Alerting/pages/Destinations/containers/CreateDestination/EmailRecipients/utils/helpers.js
+++ b/web/src/pages/Alerting/pages/Destinations/containers/CreateDestination/EmailRecipients/utils/helpers.js
@@ -17,7 +17,7 @@ import { MAX_QUERY_RESULT_SIZE } from '../../../../../../utils/constants';
export default async function getEmailGroups(httpClient, searchText = '') {
try {
- const response = await httpClient.get('../api/alerting/destinations/email_groups', {
+ const response = await httpClient.get('/alerting/destinations/email_groups', {
query: { search: searchText, size: MAX_QUERY_RESULT_SIZE },
});
if (response.ok) {
diff --git a/web/src/pages/Alerting/pages/Destinations/containers/CreateDestination/EmailSender/utils/helpers.js b/web/src/pages/Alerting/pages/Destinations/containers/CreateDestination/EmailSender/utils/helpers.js
index cfa2f2ef..a29d045a 100644
--- a/web/src/pages/Alerting/pages/Destinations/containers/CreateDestination/EmailSender/utils/helpers.js
+++ b/web/src/pages/Alerting/pages/Destinations/containers/CreateDestination/EmailSender/utils/helpers.js
@@ -17,7 +17,7 @@ import { MAX_QUERY_RESULT_SIZE } from '../../../../../../utils/constants';
export default async function getSenders(httpClient, searchText = '') {
try {
- const response = await httpClient.get('../api/alerting/destinations/email_accounts', {
+ const response = await httpClient.get('/alerting/destinations/email_accounts', {
query: { search: searchText, size: MAX_QUERY_RESULT_SIZE },
});
if (response.ok) {
diff --git a/web/src/pages/Alerting/pages/Destinations/containers/CreateDestination/ManageEmailGroups/ManageEmailGroups.js b/web/src/pages/Alerting/pages/Destinations/containers/CreateDestination/ManageEmailGroups/ManageEmailGroups.js
index b4e7e702..819034e7 100644
--- a/web/src/pages/Alerting/pages/Destinations/containers/CreateDestination/ManageEmailGroups/ManageEmailGroups.js
+++ b/web/src/pages/Alerting/pages/Destinations/containers/CreateDestination/ManageEmailGroups/ManageEmailGroups.js
@@ -119,7 +119,7 @@ export default class ManageEmailGroups extends React.Component {
emails: emailGroup.emails.map((email) => ({ email: email.label })),
};
try {
- const response = await httpClient.post(`../api/alerting/destinations/email_groups`, {
+ const response = await httpClient.post(`/alerting/destinations/email_groups`, {
body: JSON.stringify(body),
});
if (!response.ok) {
@@ -147,7 +147,7 @@ export default class ManageEmailGroups extends React.Component {
emails: updatedEmailGroup.emails.map((email) => ({ email: email.label })),
};
try {
- const response = await httpClient.put(`../api/alerting/destinations/email_groups/${id}`, {
+ const response = await httpClient.put(`/alerting/email_groups/${id}`, {
query: { ifSeqNo, ifPrimaryTerm },
body: JSON.stringify(body),
});
@@ -172,7 +172,7 @@ export default class ManageEmailGroups extends React.Component {
const { httpClient, notifications } = this.props;
const { id } = emailGroup;
try {
- const response = await httpClient.delete(`../api/alerting/destinations/email_groups/${id}`);
+ const response = await httpClient.delete(`/alerting/email_groups/${id}`);
if (!response.ok) {
this.setState({ failedEmailGroups: true });
notifications.toasts.addDanger({
diff --git a/web/src/pages/Alerting/pages/Destinations/containers/CreateDestination/ManageSenders/ManageSenders.js b/web/src/pages/Alerting/pages/Destinations/containers/CreateDestination/ManageSenders/ManageSenders.js
index 7864d6f0..efeca72a 100644
--- a/web/src/pages/Alerting/pages/Destinations/containers/CreateDestination/ManageSenders/ManageSenders.js
+++ b/web/src/pages/Alerting/pages/Destinations/containers/CreateDestination/ManageSenders/ManageSenders.js
@@ -107,7 +107,7 @@ export default class ManageSenders extends React.Component {
method: sender.method,
};
try {
- const response = await httpClient.post(`../api/alerting/destinations/email_accounts`, {
+ const response = await httpClient.post(`/alerting/destinations/email_accounts`, {
body: JSON.stringify(body),
});
if (!response.ok) {
@@ -138,7 +138,7 @@ export default class ManageSenders extends React.Component {
method: updatedSender.method,
};
try {
- const response = await httpClient.put(`../api/alerting/destinations/email_accounts/${id}`, {
+ const response = await httpClient.put(`/alerting/email_accounts/${id}`, {
query: { ifSeqNo, ifPrimaryTerm },
body: JSON.stringify(body),
});
@@ -163,7 +163,7 @@ export default class ManageSenders extends React.Component {
const { httpClient, notifications } = this.props;
const { id } = sender;
try {
- const response = await httpClient.delete(`../api/alerting/destinations/email_accounts/${id}`);
+ const response = await httpClient.delete(`/alerting/email_accounts/${id}`);
if (!response.ok) {
this.setState({ failedSenders: true });
notifications.toasts.addDanger({
diff --git a/web/src/pages/Alerting/pages/Destinations/containers/CreateDestination/utils/destinationToFormik.js b/web/src/pages/Alerting/pages/Destinations/containers/CreateDestination/utils/destinationToFormik.js
index 60c03fad..f25785d1 100644
--- a/web/src/pages/Alerting/pages/Destinations/containers/CreateDestination/utils/destinationToFormik.js
+++ b/web/src/pages/Alerting/pages/Destinations/containers/CreateDestination/utils/destinationToFormik.js
@@ -49,7 +49,7 @@ const customWebhookToFormik = ({
const getSender = async (httpClient, id) => {
try {
- const response = await httpClient.get(`../api/alerting/destinations/email_accounts/${id}`);
+ const response = await httpClient.get(`/alerting/email_accounts/${id}`);
if (response.ok) {
return response.resp;
}
@@ -62,7 +62,7 @@ const getSender = async (httpClient, id) => {
const getEmailGroup = async (httpClient, id) => {
try {
- const response = await httpClient.get(`../api/alerting/destinations/email_groups/${id}`);
+ const response = await httpClient.get(`/alerting/destinations/email_groups/${id}`);
if (response.ok) {
return response.resp;
}
diff --git a/web/src/pages/Alerting/pages/Destinations/containers/CreateDestination/utils/validations.js b/web/src/pages/Alerting/pages/Destinations/containers/CreateDestination/utils/validations.js
index 0d146b41..6ff3b58f 100644
--- a/web/src/pages/Alerting/pages/Destinations/containers/CreateDestination/utils/validations.js
+++ b/web/src/pages/Alerting/pages/Destinations/containers/CreateDestination/utils/validations.js
@@ -24,7 +24,7 @@ export const validateDestinationName = (httpClient, destinationToEdit) => async
index: INDEX.SCHEDULED_JOBS,
query: { query: { term: { 'destination.name.keyword': value } } },
};
- const response = await httpClient.post('../api/alerting/monitors/_search', {
+ const response = await httpClient.post('/alerting/monitors/_search', {
body: JSON.stringify(options),
});
if (_.get(response, 'resp.hits.total.value', 0)) {
diff --git a/web/src/pages/Alerting/pages/Destinations/containers/DestinationsList/DestinationsList.js b/web/src/pages/Alerting/pages/Destinations/containers/DestinationsList/DestinationsList.js
index 0a9e6f6e..79697b40 100644
--- a/web/src/pages/Alerting/pages/Destinations/containers/DestinationsList/DestinationsList.js
+++ b/web/src/pages/Alerting/pages/Destinations/containers/DestinationsList/DestinationsList.js
@@ -119,7 +119,7 @@ class DestinationsList extends React.Component {
query: isDeleteAllowedQuery(type, id),
index: INDEX.SCHEDULED_JOBS,
};
- const resp = await httpClient.post('../api/alerting/monitors/_search', {
+ const resp = await httpClient.post('/alerting/monitors/_search', {
body: JSON.stringify(requestBody),
});
const total = _.get(resp, 'resp.hits.total.value');
@@ -151,7 +151,7 @@ class DestinationsList extends React.Component {
const { id: destinationId } = this.state.destinationToDelete;
const { httpClient, notifications } = this.props;
try {
- const resp = await httpClient.delete(`../api/alerting/destinations/${destinationId}`);
+ const resp = await httpClient.delete(`/alerting/destinations/${destinationId}`);
if (resp.ok) {
await this.getDestinations();
} else {
@@ -214,7 +214,7 @@ class DestinationsList extends React.Component {
// search: queryParms,
// });
try {
- const resp = await httpClient.get('../api/alerting/destinations', {
+ const resp = await httpClient.get('/alerting/destinations', {
query: { from, ...params },
});
if (resp.ok) {
diff --git a/web/src/pages/Alerting/pages/Destinations/utils/helpers.js b/web/src/pages/Alerting/pages/Destinations/utils/helpers.js
index 91fa6133..c8ffe93a 100644
--- a/web/src/pages/Alerting/pages/Destinations/utils/helpers.js
+++ b/web/src/pages/Alerting/pages/Destinations/utils/helpers.js
@@ -19,7 +19,7 @@ import { backendErrorNotification } from '../../../utils/helpers';
export async function getAllowList(httpClient) {
try {
- const response = await httpClient.get('../api/alerting/_settings');
+ const response = await httpClient.get('/alerting/_settings');
if (response.ok) {
// Attempt to resolve the value of allow_list in the order of 'persistent, 'transient' and 'defaults' settings
const { defaults, transient, persistent } = response.resp;
diff --git a/web/src/pages/Alerting/pages/MonitorDetails/containers/MonitorDetails.js b/web/src/pages/Alerting/pages/MonitorDetails/containers/MonitorDetails.js
index 79ded70d..c4e1c82d 100644
--- a/web/src/pages/Alerting/pages/MonitorDetails/containers/MonitorDetails.js
+++ b/web/src/pages/Alerting/pages/MonitorDetails/containers/MonitorDetails.js
@@ -81,7 +81,7 @@ export default class MonitorDetails extends Component {
getDetector = (id) => {
const { httpClient, notifications } = this.props;
httpClient
- .get(`../api/alerting/detectors/${id}`)
+ .get(`/alerting/detectors/${id}`)
.then((resp) => {
const { ok, detector, version: detectorVersion, seqNo, primaryTerm } = resp;
if (ok) {
@@ -101,7 +101,7 @@ export default class MonitorDetails extends Component {
getMonitor = (id) => {
const { httpClient } = this.props;
httpClient
- .get(`../api/alerting/monitors/${id}`)
+ .get(`/alerting/monitors/${id}`)
.then((resp) => {
const {
ok,
@@ -148,7 +148,7 @@ export default class MonitorDetails extends Component {
const { monitor, ifSeqNo, ifPrimaryTerm } = this.state;
this.setState({ updating: true });
return httpClient
- .put(`../api/alerting/monitors/${monitorId}`, {
+ .put(`/alerting/monitors/${monitorId}`, {
query: { ifSeqNo, ifPrimaryTerm },
body: JSON.stringify({ ...monitor, ...update }),
})
diff --git a/web/src/pages/Alerting/pages/MonitorDetails/containers/MonitorHistory/MonitorHistory.js b/web/src/pages/Alerting/pages/MonitorDetails/containers/MonitorHistory/MonitorHistory.js
index 7c316846..01ad7a34 100644
--- a/web/src/pages/Alerting/pages/MonitorDetails/containers/MonitorHistory/MonitorHistory.js
+++ b/web/src/pages/Alerting/pages/MonitorDetails/containers/MonitorHistory/MonitorHistory.js
@@ -200,7 +200,7 @@ class MonitorHistory extends PureComponent {
),
index: INDEX.ALL_ALERTS,
};
- const resp = await httpClient.post('../api/alerting/monitors/_search', {
+ const resp = await httpClient.post('/alerting/monitors/_search', {
body: JSON.stringify(requestBody),
});
if (resp.ok) {
@@ -242,7 +242,7 @@ class MonitorHistory extends PureComponent {
monitorIds: monitorId,
};
- const resp = await httpClient.get('../api/alerting/alerts', { query: params });
+ const resp = await httpClient.get('/alerting/alerts', { query: params });
var alerts;
if (resp.ok) {
alerts = resp.alerts;
diff --git a/web/src/pages/Alerting/pages/MonitorDetails/containers/Triggers/Triggers.js b/web/src/pages/Alerting/pages/MonitorDetails/containers/Triggers/Triggers.js
index 63bfac1d..191f197f 100644
--- a/web/src/pages/Alerting/pages/MonitorDetails/containers/Triggers/Triggers.js
+++ b/web/src/pages/Alerting/pages/MonitorDetails/containers/Triggers/Triggers.js
@@ -15,7 +15,7 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
-import uuidv4 from 'uuidv4';
+import uuid from 'uuid-v4';
import { EuiButton, EuiInMemoryTable } from '@elastic/eui';
import ContentPanel from '../../../../components/ContentPanel';
@@ -28,7 +28,7 @@ export default class Triggers extends Component {
this.state = {
field: 'name',
- tableKey: uuidv4(),
+ tableKey: uuid(),
direction: 'asc',
selectedItems: [],
};
@@ -45,7 +45,7 @@ export default class Triggers extends Component {
// which EuiInMemoryTable uses which causes items to not be updated correctly.
// Whenever the monitor is updated we'll generate a new key for the table
// which will cause the table component to remount
- this.setState({ tableKey: uuidv4() });
+ this.setState({ tableKey: uuid() });
}
}
diff --git a/web/src/pages/Alerting/pages/Monitors/containers/Monitors/Monitors.js b/web/src/pages/Alerting/pages/Monitors/containers/Monitors/Monitors.js
index 523ac867..ae1661c8 100644
--- a/web/src/pages/Alerting/pages/Monitors/containers/Monitors/Monitors.js
+++ b/web/src/pages/Alerting/pages/Monitors/containers/Monitors/Monitors.js
@@ -144,8 +144,8 @@ export default class Monitors extends Component {
const params = { from, size, search, sortField, sortDirection, state };
const queryParamsString = queryString.stringify(params);
const { httpClient, history } = this.props;
- history.replace({ ...this.props.location, search: queryParamsString });
- const response = await httpClient.get('../api/alerting/monitors', { query: params });
+ //history.replace({ ...this.props.location, search: queryParamsString });
+ const response = await httpClient.get('/alerting/monitors', { query: params });
if (response.ok) {
const { monitors, totalMonitors } = response;
this.setState({ monitors, totalMonitors });
@@ -182,7 +182,7 @@ export default class Monitors extends Component {
const { httpClient, notifications } = this.props;
const { id, ifSeqNo, ifPrimaryTerm, monitor } = item;
return httpClient
- .put(`../api/alerting/monitors/${id}`, {
+ .put(`/alerting/monitors/${id}`, {
query: { ifSeqNo, ifPrimaryTerm },
body: JSON.stringify({ ...monitor, ...update }),
})
@@ -199,7 +199,7 @@ export default class Monitors extends Component {
const { httpClient, notifications } = this.props;
const { id, version } = item;
return httpClient
- .delete(`../api/alerting/monitors/${id}`, { query: { version } })
+ .delete(`/alerting/monitors/${id}`, { query: { version } })
.then((resp) => {
if (!resp.ok) {
backendErrorNotification(notifications, 'delete', 'monitor', resp.resp);
@@ -249,7 +249,7 @@ export default class Monitors extends Component {
const promises = Object.entries(monitorAlerts).map(([monitorId, alerts]) =>
httpClient
- .post(`../api/alerting/monitors/${monitorId}/_acknowledge/alerts`, {
+ .post(`/alerting/monitors/${monitorId}/_acknowledge/alerts`, {
body: JSON.stringify({ alerts }),
})
.then((resp) => {
@@ -321,7 +321,7 @@ export default class Monitors extends Component {
const { httpClient, notifications } = this.props;
- const response = await httpClient.get('../api/alerting/alerts', { query: params });
+ const response = await httpClient.get('/alerting/alerts', { query: params });
if (response.ok) {
const { alerts, totalAlerts } = response;
diff --git a/web/src/pages/Alerting/pages/Monitors/containers/Monitors/Monitors.test.js b/web/src/pages/Alerting/pages/Monitors/containers/Monitors/Monitors.test.js
index 60a5851b..29e520d6 100644
--- a/web/src/pages/Alerting/pages/Monitors/containers/Monitors/Monitors.test.js
+++ b/web/src/pages/Alerting/pages/Monitors/containers/Monitors/Monitors.test.js
@@ -160,7 +160,7 @@ describe('Monitors', () => {
expect(updateMonitor).toHaveBeenCalled();
expect(httpClientMock.put).toHaveBeenCalled();
- expect(httpClientMock.put).toHaveBeenCalledWith(`../api/alerting/monitors/random_id`, {
+ expect(httpClientMock.put).toHaveBeenCalledWith(`/alerting/monitors/random_id`, {
query: { ifSeqNo: 17, ifPrimaryTerm: 20 },
body: JSON.stringify({ ...monitor, name: 'UNIQUE_NAME' }),
});
diff --git a/web/src/pages/Alerting/pages/Monitors/containers/Monitors/utils/tableUtils.js b/web/src/pages/Alerting/pages/Monitors/containers/Monitors/utils/tableUtils.js
index 6ab566e6..6aeb6b27 100644
--- a/web/src/pages/Alerting/pages/Monitors/containers/Monitors/utils/tableUtils.js
+++ b/web/src/pages/Alerting/pages/Monitors/containers/Monitors/utils/tableUtils.js
@@ -34,7 +34,7 @@ export const columns = [
truncateText: true,
textOnly: true,
// width: '150px',
- render: (name, item) => {name},
+ render: (name, item) => {name},
},
{
field: 'user',
diff --git a/web/src/pages/Alerting/utils/constants.js b/web/src/pages/Alerting/utils/constants.js
index 22fca51a..cd16eec2 100644
--- a/web/src/pages/Alerting/utils/constants.js
+++ b/web/src/pages/Alerting/utils/constants.js
@@ -66,10 +66,10 @@ export const AD_PREVIEW_DAYS = 7;
export const MAX_QUERY_RESULT_SIZE = 200;
-export const OPEN_DISTRO_PREFIX = '';
+export const OPEN_DISTRO_PREFIX = 'opendistro';
export const PLUGIN_NAME = `alerting`;
-export const INDEX_PREFIX = `alerting`;
+export const INDEX_PREFIX = `${OPEN_DISTRO_PREFIX}-alerting`;
export const INDEX = {
SCHEDULED_JOBS: `.${INDEX_PREFIX}-config`,
ALERTS: `.${INDEX_PREFIX}-alerts`,
diff --git a/web/src/pages/Alerting/utils/validate.js b/web/src/pages/Alerting/utils/validate.js
index 2153882e..4fc3777d 100644
--- a/web/src/pages/Alerting/utils/validate.js
+++ b/web/src/pages/Alerting/utils/validate.js
@@ -56,7 +56,7 @@ export const validateMonitorName = (httpClient, monitorToEdit) => async (value)
index: INDEX.SCHEDULED_JOBS,
query: { query: { term: { 'monitor.name.keyword': value } } },
};
- const response = await httpClient.post('../api/alerting/monitors/_search', {
+ const response = await httpClient.post('/alerting/monitors/_search', {
body: JSON.stringify(options),
});
if (_.get(response, 'resp.hits.total.value', 0)) {