package server // TODO(desa): resolve kapacitor dependency //type postKapacitorRequest struct { // Name *string `json:"name"` // User facing name of kapacitor instance.; Required: true // URL *string `json:"url"` // URL for the kapacitor backend (e.g. http://localhost:9092);/ Required: true // Username string `json:"username,omitempty"` // Username for authentication to kapacitor // Password string `json:"password,omitempty"` // InsecureSkipVerify bool `json:"insecureSkipVerify"` // InsecureSkipVerify as true means any certificate presented by the kapacitor is accepted. // Active bool `json:"active"` // Organization string `json:"organization"` // Organization is the organization ID that resource belongs to //} // //func (p *postKapacitorRequest) Valid(defaultOrgID string) error { // if p.Name == nil || p.URL == nil { // return fmt.Errorf("name and url required") // } // // if p.Organization == "" { // p.Organization = defaultOrgID // } // // url, err := url.ParseRequestURI(*p.URL) // if err != nil { // return fmt.Errorf("invalid source URI: %v", err) // } // if len(url.Scheme) == 0 { // return fmt.Errorf("invalid URL; no URL scheme defined") // } // // return nil //} // //type kapaLinks struct { // Proxy string `json:"proxy"` // URL location of proxy endpoint for this source // Self string `json:"self"` // Self link mapping to this resource // Rules string `json:"rules"` // Rules link for defining roles alerts for kapacitor // Tasks string `json:"tasks"` // Tasks link to define a task against the proxy // Ping string `json:"ping"` // Ping path to kapacitor //} // //type kapacitor struct { // ID int `json:"id,string"` // Unique identifier representing a kapacitor instance. // Name string `json:"name"` // User facing name of kapacitor instance. // URL string `json:"url"` // URL for the kapacitor backend (e.g. http://localhost:9092) // Username string `json:"username,omitempty"` // Username for authentication to kapacitor // Password string `json:"password,omitempty"` // InsecureSkipVerify bool `json:"insecureSkipVerify"` // InsecureSkipVerify as true means any certificate presented by the kapacitor is accepted. // Active bool `json:"active"` // Links kapaLinks `json:"links"` // Links are URI locations related to kapacitor //} // //// NewKapacitor adds valid kapacitor store store. //func (s *Service) NewKapacitor(w http.ResponseWriter, r *http.Request) { // srcID, err := paramID("id", r) // if err != nil { // Error(w, http.StatusUnprocessableEntity, err.Error(), s.Logger) // return // } // // ctx := r.Context() // _, err = s.Store.Sources(ctx).Get(ctx, srcID) // if err != nil { // notFound(w, srcID, s.Logger) // return // } // // var req postKapacitorRequest // if err = json.NewDecoder(r.Body).Decode(&req); err != nil { // invalidJSON(w, s.Logger) // return // } // // defaultOrg, err := s.Store.Organizations(ctx).DefaultOrganization(ctx) // if err != nil { // unknownErrorWithMessage(w, err, s.Logger) // return // } // // if err := req.Valid(defaultOrg.ID); err != nil { // invalidData(w, err, s.Logger) // return // } // // srv := chronograf.Server{ // SrcID: srcID, // Name: *req.Name, // Username: req.Username, // Password: req.Password, // InsecureSkipVerify: req.InsecureSkipVerify, // URL: *req.URL, // Active: req.Active, // Organization: req.Organization, // } // // if srv, err = s.Store.Servers(ctx).Add(ctx, srv); err != nil { // msg := fmt.Errorf("error storing kapacitor %v: %v", req, err) // unknownErrorWithMessage(w, msg, s.Logger) // return // } // // res := newKapacitor(srv) // location(w, res.Links.Self) // encodeJSON(w, http.StatusCreated, res, s.Logger) //} // //func newKapacitor(srv chronograf.Server) kapacitor { // httpAPISrcs := "/chronograf/v1/sources" // return kapacitor{ // ID: srv.ID, // Name: srv.Name, // Username: srv.Username, // URL: srv.URL, // Active: srv.Active, // InsecureSkipVerify: srv.InsecureSkipVerify, // Links: kapaLinks{ // Self: fmt.Sprintf("%s/%d/kapacitors/%d", httpAPISrcs, srv.SrcID, srv.ID), // Proxy: fmt.Sprintf("%s/%d/kapacitors/%d/proxy", httpAPISrcs, srv.SrcID, srv.ID), // Rules: fmt.Sprintf("%s/%d/kapacitors/%d/rules", httpAPISrcs, srv.SrcID, srv.ID), // Tasks: fmt.Sprintf("%s/%d/kapacitors/%d/proxy?path=/kapacitor/v1/tasks", httpAPISrcs, srv.SrcID, srv.ID), // Ping: fmt.Sprintf("%s/%d/kapacitors/%d/proxy?path=/kapacitor/v1/ping", httpAPISrcs, srv.SrcID, srv.ID), // }, // } //} // //type kapacitors struct { // Kapacitors []kapacitor `json:"kapacitors"` //} // //// Kapacitors retrieves all kapacitors from store. //func (s *Service) Kapacitors(w http.ResponseWriter, r *http.Request) { // srcID, err := paramID("id", r) // if err != nil { // Error(w, http.StatusUnprocessableEntity, err.Error(), s.Logger) // return // } // // ctx := r.Context() // mrSrvs, err := s.Store.Servers(ctx).All(ctx) // if err != nil { // Error(w, http.StatusInternalServerError, "Error loading kapacitors", s.Logger) // return // } // // srvs := []kapacitor{} // for _, srv := range mrSrvs { // if srv.SrcID == srcID && srv.Type == "" { // srvs = append(srvs, newKapacitor(srv)) // } // } // // res := kapacitors{ // Kapacitors: srvs, // } // // encodeJSON(w, http.StatusOK, res, s.Logger) //} // //// KapacitorsID retrieves a kapacitor with ID from store. //func (s *Service) KapacitorsID(w http.ResponseWriter, r *http.Request) { // id, err := paramID("kid", r) // if err != nil { // Error(w, http.StatusUnprocessableEntity, err.Error(), s.Logger) // return // } // // srcID, err := paramID("id", r) // if err != nil { // Error(w, http.StatusUnprocessableEntity, err.Error(), s.Logger) // return // } // // ctx := r.Context() // srv, err := s.Store.Servers(ctx).Get(ctx, id) // if err != nil || srv.SrcID != srcID || srv.Type != "" { // notFound(w, id, s.Logger) // return // } // // res := newKapacitor(srv) // encodeJSON(w, http.StatusOK, res, s.Logger) //} // //// RemoveKapacitor deletes kapacitor from store. //func (s *Service) RemoveKapacitor(w http.ResponseWriter, r *http.Request) { // id, err := paramID("kid", r) // if err != nil { // Error(w, http.StatusUnprocessableEntity, err.Error(), s.Logger) // return // } // // srcID, err := paramID("id", r) // if err != nil { // Error(w, http.StatusUnprocessableEntity, err.Error(), s.Logger) // return // } // // ctx := r.Context() // srv, err := s.Store.Servers(ctx).Get(ctx, id) // if err != nil || srv.SrcID != srcID || srv.Type != "" { // notFound(w, id, s.Logger) // return // } // // if err = s.Store.Servers(ctx).Delete(ctx, srv); err != nil { // unknownErrorWithMessage(w, err, s.Logger) // return // } // // w.WriteHeader(http.StatusNoContent) //} // //type patchKapacitorRequest struct { // Name *string `json:"name,omitempty"` // User facing name of kapacitor instance. // URL *string `json:"url,omitempty"` // URL for the kapacitor // Username *string `json:"username,omitempty"` // Username for kapacitor auth // Password *string `json:"password,omitempty"` // InsecureSkipVerify *bool `json:"insecureSkipVerify"` // InsecureSkipVerify as true means any certificate presented by the kapacitor is accepted. // Active *bool `json:"active"` //} // //func (p *patchKapacitorRequest) Valid() error { // if p.URL != nil { // url, err := url.ParseRequestURI(*p.URL) // if err != nil { // return fmt.Errorf("invalid source URI: %v", err) // } // if len(url.Scheme) == 0 { // return fmt.Errorf("invalid URL; no URL scheme defined") // } // } // return nil //} // //// UpdateKapacitor incrementally updates a kapacitor definition in the store //func (s *Service) UpdateKapacitor(w http.ResponseWriter, r *http.Request) { // id, err := paramID("kid", r) // if err != nil { // Error(w, http.StatusUnprocessableEntity, err.Error(), s.Logger) // return // } // // srcID, err := paramID("id", r) // if err != nil { // Error(w, http.StatusUnprocessableEntity, err.Error(), s.Logger) // return // } // // ctx := r.Context() // srv, err := s.Store.Servers(ctx).Get(ctx, id) // if err != nil || srv.SrcID != srcID || srv.Type != "" { // notFound(w, id, s.Logger) // return // } // // var req patchKapacitorRequest // if err := json.NewDecoder(r.Body).Decode(&req); err != nil { // invalidJSON(w, s.Logger) // return // } // // if err := req.Valid(); err != nil { // invalidData(w, err, s.Logger) // return // } // // if req.Name != nil { // srv.Name = *req.Name // } // if req.URL != nil { // srv.URL = *req.URL // } // if req.Password != nil { // srv.Password = *req.Password // } // if req.Username != nil { // srv.Username = *req.Username // } // if req.InsecureSkipVerify != nil { // srv.InsecureSkipVerify = *req.InsecureSkipVerify // } // if req.Active != nil { // srv.Active = *req.Active // } // // if err := s.Store.Servers(ctx).Update(ctx, srv); err != nil { // msg := fmt.Sprintf("Error updating kapacitor ID %d", id) // Error(w, http.StatusInternalServerError, msg, s.Logger) // return // } // // res := newKapacitor(srv) // encodeJSON(w, http.StatusOK, res, s.Logger) //} // //// KapacitorRulesPost proxies POST to kapacitor //func (s *Service) KapacitorRulesPost(w http.ResponseWriter, r *http.Request) { // id, err := paramID("kid", r) // if err != nil { // Error(w, http.StatusUnprocessableEntity, err.Error(), s.Logger) // return // } // // srcID, err := paramID("id", r) // if err != nil { // Error(w, http.StatusUnprocessableEntity, err.Error(), s.Logger) // return // } // // ctx := r.Context() // srv, err := s.Store.Servers(ctx).Get(ctx, id) // if err != nil || srv.SrcID != srcID { // notFound(w, id, s.Logger) // return // } // // c := kapa.NewClient(srv.URL, srv.Username, srv.Password, srv.InsecureSkipVerify) // // var req chronograf.AlertRule // if err = json.NewDecoder(r.Body).Decode(&req); err != nil { // invalidData(w, err, s.Logger) // return // } // // TODO: validate this data // /* // if err := req.Valid(); err != nil { // invalidData(w, err) // return // } // */ // // if req.Name == "" { // req.Name = req.ID // } // // req.ID = "" // task, err := c.Create(ctx, req) // if err != nil { // invalidData(w, err, s.Logger) // return // } // res := newAlertResponse(task, srv.SrcID, srv.ID) // location(w, res.Links.Self) // encodeJSON(w, http.StatusCreated, res, s.Logger) //} // //type alertLinks struct { // Self string `json:"self"` // Kapacitor string `json:"kapacitor"` // Output string `json:"output"` //} // //type alertResponse struct { // chronograf.AlertRule // Links alertLinks `json:"links"` //} // //// newAlertResponse formats task into an alertResponse //func newAlertResponse(task *kapa.Task, srcID, kapaID int) *alertResponse { // res := &alertResponse{ // AlertRule: task.Rule, // Links: alertLinks{ // Self: fmt.Sprintf("/chronograf/v1/sources/%d/kapacitors/%d/rules/%s", srcID, kapaID, task.ID), // Kapacitor: fmt.Sprintf("/chronograf/v1/sources/%d/kapacitors/%d/proxy?path=%s", srcID, kapaID, url.QueryEscape(task.Href)), // Output: fmt.Sprintf("/chronograf/v1/sources/%d/kapacitors/%d/proxy?path=%s", srcID, kapaID, url.QueryEscape(task.HrefOutput)), // }, // } // // if res.AlertNodes.Alerta == nil { // res.AlertNodes.Alerta = []*chronograf.Alerta{} // } // // for i, a := range res.AlertNodes.Alerta { // if a.Service == nil { // a.Service = []string{} // res.AlertNodes.Alerta[i] = a // } // } // // if res.AlertNodes.Email == nil { // res.AlertNodes.Email = []*chronograf.Email{} // } // // for i, a := range res.AlertNodes.Email { // if a.To == nil { // a.To = []string{} // res.AlertNodes.Email[i] = a // } // } // // if res.AlertNodes.Exec == nil { // res.AlertNodes.Exec = []*chronograf.Exec{} // } // // for i, a := range res.AlertNodes.Exec { // if a.Command == nil { // a.Command = []string{} // res.AlertNodes.Exec[i] = a // } // } // // if res.AlertNodes.HipChat == nil { // res.AlertNodes.HipChat = []*chronograf.HipChat{} // } // // if res.AlertNodes.Kafka == nil { // res.AlertNodes.Kafka = []*chronograf.Kafka{} // } // // if res.AlertNodes.Log == nil { // res.AlertNodes.Log = []*chronograf.Log{} // } // // if res.AlertNodes.OpsGenie == nil { // res.AlertNodes.OpsGenie = []*chronograf.OpsGenie{} // } // // for i, a := range res.AlertNodes.OpsGenie { // if a.Teams == nil { // a.Teams = []string{} // res.AlertNodes.OpsGenie[i] = a // } // // if a.Recipients == nil { // a.Recipients = []string{} // res.AlertNodes.OpsGenie[i] = a // } // } // // if res.AlertNodes.OpsGenie2 == nil { // res.AlertNodes.OpsGenie2 = []*chronograf.OpsGenie{} // } // // for i, a := range res.AlertNodes.OpsGenie2 { // if a.Teams == nil { // a.Teams = []string{} // res.AlertNodes.OpsGenie2[i] = a // } // // if a.Recipients == nil { // a.Recipients = []string{} // res.AlertNodes.OpsGenie2[i] = a // } // } // // if res.AlertNodes.PagerDuty == nil { // res.AlertNodes.PagerDuty = []*chronograf.PagerDuty{} // } // // if res.AlertNodes.PagerDuty2 == nil { // res.AlertNodes.PagerDuty2 = []*chronograf.PagerDuty{} // } // // if res.AlertNodes.Posts == nil { // res.AlertNodes.Posts = []*chronograf.Post{} // } // // for i, a := range res.AlertNodes.Posts { // if a.Headers == nil { // a.Headers = map[string]string{} // res.AlertNodes.Posts[i] = a // } // } // // if res.AlertNodes.Pushover == nil { // res.AlertNodes.Pushover = []*chronograf.Pushover{} // } // // if res.AlertNodes.Sensu == nil { // res.AlertNodes.Sensu = []*chronograf.Sensu{} // } // // for i, a := range res.AlertNodes.Sensu { // if a.Handlers == nil { // a.Handlers = []string{} // res.AlertNodes.Sensu[i] = a // } // } // // if res.AlertNodes.Slack == nil { // res.AlertNodes.Slack = []*chronograf.Slack{} // } // // if res.AlertNodes.Talk == nil { // res.AlertNodes.Talk = []*chronograf.Talk{} // } // // if res.AlertNodes.TCPs == nil { // res.AlertNodes.TCPs = []*chronograf.TCP{} // } // // if res.AlertNodes.Telegram == nil { // res.AlertNodes.Telegram = []*chronograf.Telegram{} // } // // if res.AlertNodes.VictorOps == nil { // res.AlertNodes.VictorOps = []*chronograf.VictorOps{} // } // // if res.Query != nil { // if res.Query.ID == "" { // res.Query.ID = res.ID // } // // if res.Query.Fields == nil { // res.Query.Fields = make([]chronograf.Field, 0) // } // // if res.Query.GroupBy.Tags == nil { // res.Query.GroupBy.Tags = make([]string, 0) // } // // if res.Query.Tags == nil { // res.Query.Tags = make(map[string][]string) // } // } // return res //} // //// ValidRuleRequest checks if the requested rule change is valid //func ValidRuleRequest(rule chronograf.AlertRule) error { // if rule.Query == nil { // return fmt.Errorf("invalid alert rule: no query defined") // } // var hasFuncs bool // for _, f := range rule.Query.Fields { // if f.Type == "func" && len(f.Args) > 0 { // hasFuncs = true // } // } // // All kapacitor rules with functions must have a window that is applied // // every amount of time // if rule.Every == "" && hasFuncs { // return fmt.Errorf(`invalid alert rule: functions require an "every" window`) // } // return nil //} // //// KapacitorRulesPut proxies PATCH to kapacitor //func (s *Service) KapacitorRulesPut(w http.ResponseWriter, r *http.Request) { // id, err := paramID("kid", r) // if err != nil { // Error(w, http.StatusUnprocessableEntity, err.Error(), s.Logger) // return // } // // srcID, err := paramID("id", r) // if err != nil { // Error(w, http.StatusUnprocessableEntity, err.Error(), s.Logger) // return // } // // ctx := r.Context() // srv, err := s.Store.Servers(ctx).Get(ctx, id) // if err != nil || srv.SrcID != srcID { // notFound(w, id, s.Logger) // return // } // // tid := httprouter.GetParamFromContext(ctx, "tid") // c := kapa.NewClient(srv.URL, srv.Username, srv.Password, srv.InsecureSkipVerify) // var req chronograf.AlertRule // if err = json.NewDecoder(r.Body).Decode(&req); err != nil { // invalidData(w, err, s.Logger) // return // } // // TODO: validate this data // /* // if err := req.Valid(); err != nil { // invalidData(w, err) // return // } // */ // // // Check if the rule exists and is scoped correctly // if _, err = c.Get(ctx, tid); err != nil { // if err == chronograf.ErrAlertNotFound { // notFound(w, id, s.Logger) // return // } // Error(w, http.StatusInternalServerError, err.Error(), s.Logger) // return // } // // // Replace alert completely with this new alert. // req.ID = tid // task, err := c.Update(ctx, c.Href(tid), req) // if err != nil { // invalidData(w, err, s.Logger) // return // } // res := newAlertResponse(task, srv.SrcID, srv.ID) // encodeJSON(w, http.StatusOK, res, s.Logger) //} // //// KapacitorStatus is the current state of a running task //type KapacitorStatus struct { // Status string `json:"status"` //} // //// Valid check if the kapacitor status is enabled or disabled //func (k *KapacitorStatus) Valid() error { // if k.Status == "enabled" || k.Status == "disabled" { // return nil // } // return fmt.Errorf("invalid Kapacitor status: %s", k.Status) //} // //// KapacitorRulesStatus proxies PATCH to kapacitor to enable/disable tasks //func (s *Service) KapacitorRulesStatus(w http.ResponseWriter, r *http.Request) { // id, err := paramID("kid", r) // if err != nil { // Error(w, http.StatusUnprocessableEntity, err.Error(), s.Logger) // return // } // // srcID, err := paramID("id", r) // if err != nil { // Error(w, http.StatusUnprocessableEntity, err.Error(), s.Logger) // return // } // // ctx := r.Context() // srv, err := s.Store.Servers(ctx).Get(ctx, id) // if err != nil || srv.SrcID != srcID { // notFound(w, id, s.Logger) // return // } // // tid := httprouter.GetParamFromContext(ctx, "tid") // c := kapa.NewClient(srv.URL, srv.Username, srv.Password, srv.InsecureSkipVerify) // // var req KapacitorStatus // if err = json.NewDecoder(r.Body).Decode(&req); err != nil { // invalidJSON(w, s.Logger) // return // } // if err := req.Valid(); err != nil { // invalidData(w, err, s.Logger) // return // } // // // Check if the rule exists and is scoped correctly // _, err = c.Get(ctx, tid) // if err != nil { // if err == chronograf.ErrAlertNotFound { // notFound(w, id, s.Logger) // return // } // Error(w, http.StatusInternalServerError, err.Error(), s.Logger) // return // } // // var task *kapa.Task // if req.Status == "enabled" { // task, err = c.Enable(ctx, c.Href(tid)) // } else { // task, err = c.Disable(ctx, c.Href(tid)) // } // // if err != nil { // Error(w, http.StatusInternalServerError, err.Error(), s.Logger) // return // } // // res := newAlertResponse(task, srv.SrcID, srv.ID) // encodeJSON(w, http.StatusOK, res, s.Logger) //} // //// KapacitorRulesGet retrieves all rules //func (s *Service) KapacitorRulesGet(w http.ResponseWriter, r *http.Request) { // id, err := paramID("kid", r) // if err != nil { // Error(w, http.StatusUnprocessableEntity, err.Error(), s.Logger) // return // } // // srcID, err := paramID("id", r) // if err != nil { // Error(w, http.StatusUnprocessableEntity, err.Error(), s.Logger) // return // } // // ctx := r.Context() // srv, err := s.Store.Servers(ctx).Get(ctx, id) // if err != nil || srv.SrcID != srcID { // notFound(w, id, s.Logger) // return // } // // c := kapa.NewClient(srv.URL, srv.Username, srv.Password, srv.InsecureSkipVerify) // tasks, err := c.All(ctx) // if err != nil { // Error(w, http.StatusInternalServerError, err.Error(), s.Logger) // return // } // // res := allAlertsResponse{ // Rules: []*alertResponse{}, // } // for _, task := range tasks { // ar := newAlertResponse(task, srv.SrcID, srv.ID) // res.Rules = append(res.Rules, ar) // } // encodeJSON(w, http.StatusOK, res, s.Logger) //} // //type allAlertsResponse struct { // Rules []*alertResponse `json:"rules"` //} // //// KapacitorRulesID retrieves specific task //func (s *Service) KapacitorRulesID(w http.ResponseWriter, r *http.Request) { // id, err := paramID("kid", r) // if err != nil { // Error(w, http.StatusUnprocessableEntity, err.Error(), s.Logger) // return // } // // srcID, err := paramID("id", r) // if err != nil { // Error(w, http.StatusUnprocessableEntity, err.Error(), s.Logger) // return // } // // ctx := r.Context() // srv, err := s.Store.Servers(ctx).Get(ctx, id) // if err != nil || srv.SrcID != srcID { // notFound(w, id, s.Logger) // return // } // tid := httprouter.GetParamFromContext(ctx, "tid") // // c := kapa.NewClient(srv.URL, srv.Username, srv.Password, srv.InsecureSkipVerify) // // // Check if the rule exists within scope // task, err := c.Get(ctx, tid) // if err != nil { // if err == chronograf.ErrAlertNotFound { // notFound(w, id, s.Logger) // return // } // Error(w, http.StatusInternalServerError, err.Error(), s.Logger) // return // } // // res := newAlertResponse(task, srv.SrcID, srv.ID) // encodeJSON(w, http.StatusOK, res, s.Logger) //} // //// KapacitorRulesDelete proxies DELETE to kapacitor //func (s *Service) KapacitorRulesDelete(w http.ResponseWriter, r *http.Request) { // id, err := paramID("kid", r) // if err != nil { // Error(w, http.StatusUnprocessableEntity, err.Error(), s.Logger) // return // } // // srcID, err := paramID("id", r) // if err != nil { // Error(w, http.StatusUnprocessableEntity, err.Error(), s.Logger) // return // } // // ctx := r.Context() // srv, err := s.Store.Servers(ctx).Get(ctx, id) // if err != nil || srv.SrcID != srcID { // notFound(w, id, s.Logger) // return // } // // c := kapa.NewClient(srv.URL, srv.Username, srv.Password, srv.InsecureSkipVerify) // // tid := httprouter.GetParamFromContext(ctx, "tid") // // Check if the rule is linked to this server and kapacitor // if _, err := c.Get(ctx, tid); err != nil { // if err == chronograf.ErrAlertNotFound { // notFound(w, id, s.Logger) // return // } // Error(w, http.StatusInternalServerError, err.Error(), s.Logger) // return // } // if err := c.Delete(ctx, c.Href(tid)); err != nil { // Error(w, http.StatusInternalServerError, err.Error(), s.Logger) // return // } // // w.WriteHeader(http.StatusNoContent) //}