2016-10-25 15:20:06 +00:00
package server
import (
"encoding/json"
"fmt"
"net/http"
"net/url"
2016-11-03 06:42:52 +00:00
"github.com/bouk/httprouter"
2016-10-25 15:20:06 +00:00
"github.com/influxdata/chronograf"
2016-11-03 06:42:52 +00:00
kapa "github.com/influxdata/chronograf/kapacitor"
2016-10-25 15:20:06 +00:00
)
type postKapacitorRequest struct {
2017-10-20 03:48:31 +00:00
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,omitempty" ` // InsecureSkipVerify as true means any certificate presented by the kapacitor is accepted.
Active bool ` json:"active" `
2017-11-14 08:05:18 +00:00
Organization string ` json:"organization" ` // Organization is the organization ID that resource belongs to
2016-10-25 15:20:06 +00:00
}
2017-11-02 20:47:45 +00:00
func ( p * postKapacitorRequest ) Valid ( defaultOrgID string ) error {
2016-10-25 15:20:06 +00:00
if p . Name == nil || p . URL == nil {
return fmt . Errorf ( "name and url required" )
}
2017-10-25 18:48:19 +00:00
if p . Organization == "" {
2017-11-02 20:47:45 +00:00
p . Organization = defaultOrgID
2017-10-25 18:48:19 +00:00
}
2016-10-25 15:20:06 +00:00
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
2016-11-10 17:27:42 +00:00
Rules string ` json:"rules" ` // Rules link for defining roles alerts for kapacitor
2017-07-14 18:37:39 +00:00
Tasks string ` json:"tasks" ` // Tasks link to define a task against the proxy
Ping string ` json:"ping" ` // Ping path to kapacitor
2016-10-25 15:20:06 +00:00
}
type kapacitor struct {
2017-10-20 03:48:31 +00:00
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,omitempty" ` // 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
2016-10-25 15:20:06 +00:00
}
2016-10-28 16:27:06 +00:00
// NewKapacitor adds valid kapacitor store store.
2017-10-10 22:27:58 +00:00
func ( s * Service ) NewKapacitor ( w http . ResponseWriter , r * http . Request ) {
2016-10-25 15:20:06 +00:00
srcID , err := paramID ( "id" , r )
if err != nil {
2017-10-10 22:27:58 +00:00
Error ( w , http . StatusUnprocessableEntity , err . Error ( ) , s . Logger )
2016-10-25 15:20:06 +00:00
return
}
ctx := r . Context ( )
2017-10-31 20:41:17 +00:00
_ , err = s . Store . Sources ( ctx ) . Get ( ctx , srcID )
2016-10-25 15:20:06 +00:00
if err != nil {
2017-10-10 22:27:58 +00:00
notFound ( w , srcID , s . Logger )
2016-10-25 15:20:06 +00:00
return
}
var req postKapacitorRequest
if err = json . NewDecoder ( r . Body ) . Decode ( & req ) ; err != nil {
2017-10-10 22:27:58 +00:00
invalidJSON ( w , s . Logger )
2016-10-25 15:20:06 +00:00
return
}
2017-11-02 20:47:45 +00:00
defaultOrg , err := s . Store . Organizations ( ctx ) . DefaultOrganization ( ctx )
if err != nil {
unknownErrorWithMessage ( w , err , s . Logger )
return
}
2017-12-18 22:07:40 +00:00
if err := req . Valid ( defaultOrg . ID ) ; err != nil {
2017-10-10 22:27:58 +00:00
invalidData ( w , err , s . Logger )
2016-10-25 15:20:06 +00:00
return
}
srv := chronograf . Server {
2017-10-20 03:48:31 +00:00
SrcID : srcID ,
Name : * req . Name ,
Username : req . Username ,
Password : req . Password ,
InsecureSkipVerify : req . InsecureSkipVerify ,
URL : * req . URL ,
Active : req . Active ,
2017-11-14 08:05:18 +00:00
Organization : req . Organization ,
2016-10-25 15:20:06 +00:00
}
2017-10-31 20:41:17 +00:00
if srv , err = s . Store . Servers ( ctx ) . Add ( ctx , srv ) ; err != nil {
2016-10-25 15:20:06 +00:00
msg := fmt . Errorf ( "Error storing kapacitor %v: %v" , req , err )
2017-10-10 22:27:58 +00:00
unknownErrorWithMessage ( w , msg , s . Logger )
2016-10-25 15:20:06 +00:00
return
}
res := newKapacitor ( srv )
2017-10-11 17:14:57 +00:00
location ( w , res . Links . Self )
2017-10-10 22:27:58 +00:00
encodeJSON ( w , http . StatusCreated , res , s . Logger )
2016-10-25 15:20:06 +00:00
}
func newKapacitor ( srv chronograf . Server ) kapacitor {
2016-10-28 16:27:06 +00:00
httpAPISrcs := "/chronograf/v1/sources"
2016-10-25 15:20:06 +00:00
return kapacitor {
2017-10-20 03:48:31 +00:00
ID : srv . ID ,
Name : srv . Name ,
Username : srv . Username ,
URL : srv . URL ,
Active : srv . Active ,
InsecureSkipVerify : srv . InsecureSkipVerify ,
2016-10-25 15:20:06 +00:00
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 ) ,
2016-11-04 06:53:54 +00:00
Rules : fmt . Sprintf ( "%s/%d/kapacitors/%d/rules" , httpAPISrcs , srv . SrcID , srv . ID ) ,
2017-07-14 18:37:39 +00:00
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 ) ,
2016-10-25 15:20:06 +00:00
} ,
}
}
type kapacitors struct {
Kapacitors [ ] kapacitor ` json:"kapacitors" `
}
2016-10-28 16:27:06 +00:00
// Kapacitors retrieves all kapacitors from store.
2017-10-10 22:27:58 +00:00
func ( s * Service ) Kapacitors ( w http . ResponseWriter , r * http . Request ) {
2017-01-05 20:47:44 +00:00
srcID , err := paramID ( "id" , r )
if err != nil {
2017-10-10 22:27:58 +00:00
Error ( w , http . StatusUnprocessableEntity , err . Error ( ) , s . Logger )
2017-01-05 20:47:44 +00:00
return
}
2016-10-25 15:20:06 +00:00
ctx := r . Context ( )
2017-10-31 20:41:17 +00:00
mrSrvs , err := s . Store . Servers ( ctx ) . All ( ctx )
2016-10-25 15:20:06 +00:00
if err != nil {
2017-10-10 22:27:58 +00:00
Error ( w , http . StatusInternalServerError , "Error loading kapacitors" , s . Logger )
2016-10-25 15:20:06 +00:00
return
}
2017-01-05 20:47:44 +00:00
srvs := [ ] kapacitor { }
for _ , srv := range mrSrvs {
if srv . SrcID == srcID {
srvs = append ( srvs , newKapacitor ( srv ) )
}
2016-10-25 15:20:06 +00:00
}
res := kapacitors {
Kapacitors : srvs ,
}
2017-10-10 22:27:58 +00:00
encodeJSON ( w , http . StatusOK , res , s . Logger )
2016-10-25 15:20:06 +00:00
}
2016-10-28 16:27:06 +00:00
// KapacitorsID retrieves a kapacitor with ID from store.
2017-10-10 22:27:58 +00:00
func ( s * Service ) KapacitorsID ( w http . ResponseWriter , r * http . Request ) {
2016-10-25 15:20:06 +00:00
id , err := paramID ( "kid" , r )
if err != nil {
2017-10-10 22:27:58 +00:00
Error ( w , http . StatusUnprocessableEntity , err . Error ( ) , s . Logger )
2016-10-25 15:20:06 +00:00
return
}
srcID , err := paramID ( "id" , r )
if err != nil {
2017-10-10 22:27:58 +00:00
Error ( w , http . StatusUnprocessableEntity , err . Error ( ) , s . Logger )
2016-10-25 15:20:06 +00:00
return
}
ctx := r . Context ( )
2017-10-31 20:41:17 +00:00
srv , err := s . Store . Servers ( ctx ) . Get ( ctx , id )
2016-10-25 15:20:06 +00:00
if err != nil || srv . SrcID != srcID {
2017-10-10 22:27:58 +00:00
notFound ( w , id , s . Logger )
2016-10-25 15:20:06 +00:00
return
}
res := newKapacitor ( srv )
2017-10-10 22:27:58 +00:00
encodeJSON ( w , http . StatusOK , res , s . Logger )
2016-10-25 15:20:06 +00:00
}
2016-10-28 16:27:06 +00:00
// RemoveKapacitor deletes kapacitor from store.
2017-10-10 22:27:58 +00:00
func ( s * Service ) RemoveKapacitor ( w http . ResponseWriter , r * http . Request ) {
2016-10-25 15:20:06 +00:00
id , err := paramID ( "kid" , r )
if err != nil {
2017-10-10 22:27:58 +00:00
Error ( w , http . StatusUnprocessableEntity , err . Error ( ) , s . Logger )
2016-10-25 15:20:06 +00:00
return
}
srcID , err := paramID ( "id" , r )
if err != nil {
2017-10-10 22:27:58 +00:00
Error ( w , http . StatusUnprocessableEntity , err . Error ( ) , s . Logger )
2016-10-25 15:20:06 +00:00
return
}
ctx := r . Context ( )
2017-10-31 20:41:17 +00:00
srv , err := s . Store . Servers ( ctx ) . Get ( ctx , id )
2016-10-25 15:20:06 +00:00
if err != nil || srv . SrcID != srcID {
2017-10-10 22:27:58 +00:00
notFound ( w , id , s . Logger )
2016-10-25 15:20:06 +00:00
return
}
2017-10-31 20:41:17 +00:00
if err = s . Store . Servers ( ctx ) . Delete ( ctx , srv ) ; err != nil {
2017-10-10 22:27:58 +00:00
unknownErrorWithMessage ( w , err , s . Logger )
2016-10-25 15:20:06 +00:00
return
}
2017-01-05 20:47:44 +00:00
2016-10-25 15:20:06 +00:00
w . WriteHeader ( http . StatusNoContent )
}
type patchKapacitorRequest struct {
2017-10-20 03:48:31 +00:00
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,omitempty" ` // InsecureSkipVerify as true means any certificate presented by the kapacitor is accepted.
Active * bool ` json:"active" `
2016-10-25 15:20:06 +00:00
}
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
}
2016-10-28 16:27:06 +00:00
// UpdateKapacitor incrementally updates a kapacitor definition in the store
2017-10-10 22:27:58 +00:00
func ( s * Service ) UpdateKapacitor ( w http . ResponseWriter , r * http . Request ) {
2016-10-25 15:20:06 +00:00
id , err := paramID ( "kid" , r )
if err != nil {
2017-10-10 22:27:58 +00:00
Error ( w , http . StatusUnprocessableEntity , err . Error ( ) , s . Logger )
2016-10-25 15:20:06 +00:00
return
}
srcID , err := paramID ( "id" , r )
if err != nil {
2017-10-10 22:27:58 +00:00
Error ( w , http . StatusUnprocessableEntity , err . Error ( ) , s . Logger )
2016-10-25 15:20:06 +00:00
return
}
ctx := r . Context ( )
2017-10-31 20:41:17 +00:00
srv , err := s . Store . Servers ( ctx ) . Get ( ctx , id )
2016-10-25 15:20:06 +00:00
if err != nil || srv . SrcID != srcID {
2017-10-10 22:27:58 +00:00
notFound ( w , id , s . Logger )
2016-10-25 15:20:06 +00:00
return
}
var req patchKapacitorRequest
if err := json . NewDecoder ( r . Body ) . Decode ( & req ) ; err != nil {
2017-10-10 22:27:58 +00:00
invalidJSON ( w , s . Logger )
2016-10-25 15:20:06 +00:00
return
}
if err := req . Valid ( ) ; err != nil {
2017-10-10 22:27:58 +00:00
invalidData ( w , err , s . Logger )
2016-10-25 15:20:06 +00:00
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
}
2017-10-20 03:48:31 +00:00
if req . InsecureSkipVerify != nil {
srv . InsecureSkipVerify = * req . InsecureSkipVerify
}
2017-04-21 09:05:39 +00:00
if req . Active != nil {
srv . Active = * req . Active
}
2016-10-25 15:20:06 +00:00
2017-10-31 20:41:17 +00:00
if err := s . Store . Servers ( ctx ) . Update ( ctx , srv ) ; err != nil {
2016-10-25 15:20:06 +00:00
msg := fmt . Sprintf ( "Error updating kapacitor ID %d" , id )
2017-10-10 22:27:58 +00:00
Error ( w , http . StatusInternalServerError , msg , s . Logger )
2016-10-25 15:20:06 +00:00
return
}
res := newKapacitor ( srv )
2017-10-10 22:27:58 +00:00
encodeJSON ( w , http . StatusOK , res , s . Logger )
2016-10-25 15:20:06 +00:00
}
2016-10-31 23:11:05 +00:00
2016-11-04 06:53:54 +00:00
// KapacitorRulesPost proxies POST to kapacitor
2017-10-10 22:27:58 +00:00
func ( s * Service ) KapacitorRulesPost ( w http . ResponseWriter , r * http . Request ) {
2016-11-03 06:42:52 +00:00
id , err := paramID ( "kid" , r )
if err != nil {
2017-10-10 22:27:58 +00:00
Error ( w , http . StatusUnprocessableEntity , err . Error ( ) , s . Logger )
2016-11-03 06:42:52 +00:00
return
}
srcID , err := paramID ( "id" , r )
if err != nil {
2017-10-10 22:27:58 +00:00
Error ( w , http . StatusUnprocessableEntity , err . Error ( ) , s . Logger )
2016-11-03 06:42:52 +00:00
return
}
ctx := r . Context ( )
2017-10-31 20:41:17 +00:00
srv , err := s . Store . Servers ( ctx ) . Get ( ctx , id )
2016-11-03 06:42:52 +00:00
if err != nil || srv . SrcID != srcID {
2017-10-10 22:27:58 +00:00
notFound ( w , id , s . Logger )
2016-11-03 06:42:52 +00:00
return
}
2017-10-20 03:48:31 +00:00
c := kapa . NewClient ( srv . URL , srv . Username , srv . Password , srv . InsecureSkipVerify )
2016-11-03 06:42:52 +00:00
2016-11-04 00:44:28 +00:00
var req chronograf . AlertRule
if err = json . NewDecoder ( r . Body ) . Decode ( & req ) ; err != nil {
2017-10-10 22:27:58 +00:00
invalidJSON ( w , s . Logger )
2016-11-04 00:44:28 +00:00
return
}
// TODO: validate this data
/ *
if err := req . Valid ( ) ; err != nil {
invalidData ( w , err )
return
}
* /
task , err := c . Create ( ctx , req )
2016-11-03 06:42:52 +00:00
if err != nil {
2017-10-10 22:27:58 +00:00
Error ( w , http . StatusInternalServerError , err . Error ( ) , s . Logger )
2016-11-03 06:42:52 +00:00
return
}
2017-07-25 14:57:46 +00:00
res := newAlertResponse ( task , srv . SrcID , srv . ID )
2017-10-11 17:14:57 +00:00
location ( w , res . Links . Self )
2017-10-10 22:27:58 +00:00
encodeJSON ( w , http . StatusCreated , res , s . Logger )
2016-11-04 00:44:28 +00:00
}
type alertLinks struct {
Self string ` json:"self" `
Kapacitor string ` json:"kapacitor" `
2016-11-10 17:27:42 +00:00
Output string ` json:"output" `
2016-11-04 00:44:28 +00:00
}
2016-11-03 06:42:52 +00:00
2016-11-04 00:44:28 +00:00
type alertResponse struct {
chronograf . AlertRule
2017-09-07 23:02:52 +00:00
Links alertLinks ` json:"links" `
2016-10-31 23:11:05 +00:00
}
2017-04-06 01:04:42 +00:00
// newAlertResponse formats task into an alertResponse
2017-07-25 14:57:46 +00:00
func newAlertResponse ( task * kapa . Task , srcID , kapaID int ) * alertResponse {
res := & alertResponse {
AlertRule : task . Rule ,
2017-04-06 01:04:42 +00:00
Links : alertLinks {
2017-07-25 14:57:46 +00:00
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 ) ) ,
2017-04-06 01:04:42 +00:00
} ,
}
2017-05-05 19:30:20 +00:00
if res . Alerts == nil {
res . Alerts = make ( [ ] string , 0 )
2017-04-06 01:04:42 +00:00
}
2017-05-05 19:30:20 +00:00
if res . AlertNodes == nil {
res . AlertNodes = make ( [ ] chronograf . KapacitorNode , 0 )
2017-04-06 01:04:42 +00:00
}
2017-05-05 19:30:20 +00:00
for _ , n := range res . AlertNodes {
2017-04-06 01:04:42 +00:00
if n . Args == nil {
n . Args = make ( [ ] string , 0 )
}
if n . Properties == nil {
n . Properties = make ( [ ] chronograf . KapacitorProperty , 0 )
}
for _ , p := range n . Properties {
if p . Args == nil {
p . Args = make ( [ ] string , 0 )
}
}
}
2017-05-05 19:30:20 +00:00
if res . Query != nil {
if res . Query . ID == "" {
res . Query . ID = res . ID
}
2017-04-06 01:04:42 +00:00
2017-05-05 19:30:20 +00:00
if res . Query . Fields == nil {
res . Query . Fields = make ( [ ] chronograf . Field , 0 )
2017-04-06 01:04:42 +00:00
}
2017-05-05 19:30:20 +00:00
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 )
}
2017-04-06 01:04:42 +00:00
}
return res
}
2017-05-25 17:10:25 +00:00
// 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 {
2017-10-10 22:01:50 +00:00
if f . Type == "func" && len ( f . Args ) > 0 {
2017-05-25 17:10:25 +00:00
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
}
2016-11-04 06:53:54 +00:00
// KapacitorRulesPut proxies PATCH to kapacitor
2017-10-10 22:27:58 +00:00
func ( s * Service ) KapacitorRulesPut ( w http . ResponseWriter , r * http . Request ) {
2016-11-03 06:42:52 +00:00
id , err := paramID ( "kid" , r )
if err != nil {
2017-10-10 22:27:58 +00:00
Error ( w , http . StatusUnprocessableEntity , err . Error ( ) , s . Logger )
2016-11-03 06:42:52 +00:00
return
}
srcID , err := paramID ( "id" , r )
if err != nil {
2017-10-10 22:27:58 +00:00
Error ( w , http . StatusUnprocessableEntity , err . Error ( ) , s . Logger )
2016-11-03 06:42:52 +00:00
return
}
ctx := r . Context ( )
2017-10-31 20:41:17 +00:00
srv , err := s . Store . Servers ( ctx ) . Get ( ctx , id )
2016-11-03 06:42:52 +00:00
if err != nil || srv . SrcID != srcID {
2017-10-10 22:27:58 +00:00
notFound ( w , id , s . Logger )
2016-11-03 06:42:52 +00:00
return
}
tid := httprouter . GetParamFromContext ( ctx , "tid" )
2017-10-20 03:48:31 +00:00
c := kapa . NewClient ( srv . URL , srv . Username , srv . Password , srv . InsecureSkipVerify )
2016-11-04 00:44:28 +00:00
var req chronograf . AlertRule
if err = json . NewDecoder ( r . Body ) . Decode ( & req ) ; err != nil {
2017-10-10 22:27:58 +00:00
invalidJSON ( w , s . Logger )
2016-11-04 00:44:28 +00:00
return
}
// TODO: validate this data
/ *
if err := req . Valid ( ) ; err != nil {
invalidData ( w , err )
return
}
* /
2016-11-04 06:53:54 +00:00
// Check if the rule exists and is scoped correctly
2017-04-06 01:04:42 +00:00
if _ , err = c . Get ( ctx , tid ) ; err != nil {
2016-11-04 01:56:42 +00:00
if err == chronograf . ErrAlertNotFound {
2017-10-10 22:27:58 +00:00
notFound ( w , id , s . Logger )
2016-11-04 01:56:42 +00:00
return
}
2017-10-10 22:27:58 +00:00
Error ( w , http . StatusInternalServerError , err . Error ( ) , s . Logger )
2016-11-04 01:56:42 +00:00
return
}
2017-04-06 01:04:42 +00:00
// Replace alert completely with this new alert.
2016-11-04 00:44:28 +00:00
req . ID = tid
task , err := c . Update ( ctx , c . Href ( tid ) , req )
2016-11-03 06:42:52 +00:00
if err != nil {
2017-10-10 22:27:58 +00:00
Error ( w , http . StatusInternalServerError , err . Error ( ) , s . Logger )
2016-11-03 06:42:52 +00:00
return
}
2017-07-25 14:57:46 +00:00
res := newAlertResponse ( task , srv . SrcID , srv . ID )
2017-10-10 22:27:58 +00:00
encodeJSON ( w , http . StatusOK , res , s . Logger )
2017-02-10 19:48:42 +00:00
}
2017-02-22 03:35:24 +00:00
// KapacitorStatus is the current state of a running task
2017-02-10 19:48:42 +00:00
type KapacitorStatus struct {
Status string ` json:"status" `
}
2017-02-22 03:35:24 +00:00
// Valid check if the kapacitor status is enabled or disabled
2017-02-10 19:48:42 +00:00
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
2017-10-10 22:27:58 +00:00
func ( s * Service ) KapacitorRulesStatus ( w http . ResponseWriter , r * http . Request ) {
2017-02-10 19:48:42 +00:00
id , err := paramID ( "kid" , r )
if err != nil {
2017-10-10 22:27:58 +00:00
Error ( w , http . StatusUnprocessableEntity , err . Error ( ) , s . Logger )
2017-02-10 19:48:42 +00:00
return
}
srcID , err := paramID ( "id" , r )
if err != nil {
2017-10-10 22:27:58 +00:00
Error ( w , http . StatusUnprocessableEntity , err . Error ( ) , s . Logger )
2017-02-10 19:48:42 +00:00
return
}
ctx := r . Context ( )
2017-10-31 20:41:17 +00:00
srv , err := s . Store . Servers ( ctx ) . Get ( ctx , id )
2017-02-10 19:48:42 +00:00
if err != nil || srv . SrcID != srcID {
2017-10-10 22:27:58 +00:00
notFound ( w , id , s . Logger )
2017-02-10 19:48:42 +00:00
return
}
tid := httprouter . GetParamFromContext ( ctx , "tid" )
2017-10-20 03:48:31 +00:00
c := kapa . NewClient ( srv . URL , srv . Username , srv . Password , srv . InsecureSkipVerify )
2017-05-05 21:14:02 +00:00
2017-02-10 19:48:42 +00:00
var req KapacitorStatus
if err = json . NewDecoder ( r . Body ) . Decode ( & req ) ; err != nil {
2017-10-10 22:27:58 +00:00
invalidJSON ( w , s . Logger )
2017-02-10 19:48:42 +00:00
return
}
if err := req . Valid ( ) ; err != nil {
2017-10-10 22:27:58 +00:00
invalidData ( w , err , s . Logger )
2017-02-10 19:48:42 +00:00
return
}
// Check if the rule exists and is scoped correctly
2017-07-25 14:57:46 +00:00
_ , err = c . Get ( ctx , tid )
2017-02-10 19:48:42 +00:00
if err != nil {
if err == chronograf . ErrAlertNotFound {
2017-10-10 22:27:58 +00:00
notFound ( w , id , s . Logger )
2017-02-10 19:48:42 +00:00
return
}
2017-10-10 22:27:58 +00:00
Error ( w , http . StatusInternalServerError , err . Error ( ) , s . Logger )
2017-02-10 19:48:42 +00:00
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 {
2017-10-10 22:27:58 +00:00
Error ( w , http . StatusInternalServerError , err . Error ( ) , s . Logger )
2017-02-10 19:48:42 +00:00
return
}
2017-07-25 14:57:46 +00:00
res := newAlertResponse ( task , srv . SrcID , srv . ID )
2017-10-10 22:27:58 +00:00
encodeJSON ( w , http . StatusOK , res , s . Logger )
2016-10-31 23:11:05 +00:00
}
2016-11-04 06:53:54 +00:00
// KapacitorRulesGet retrieves all rules
2017-10-10 22:27:58 +00:00
func ( s * Service ) KapacitorRulesGet ( w http . ResponseWriter , r * http . Request ) {
2016-11-03 06:42:52 +00:00
id , err := paramID ( "kid" , r )
if err != nil {
2017-10-10 22:27:58 +00:00
Error ( w , http . StatusUnprocessableEntity , err . Error ( ) , s . Logger )
2016-11-03 06:42:52 +00:00
return
}
srcID , err := paramID ( "id" , r )
if err != nil {
2017-10-10 22:27:58 +00:00
Error ( w , http . StatusUnprocessableEntity , err . Error ( ) , s . Logger )
2016-11-03 06:42:52 +00:00
return
}
ctx := r . Context ( )
2017-10-31 20:41:17 +00:00
srv , err := s . Store . Servers ( ctx ) . Get ( ctx , id )
2016-11-03 06:42:52 +00:00
if err != nil || srv . SrcID != srcID {
2017-10-10 22:27:58 +00:00
notFound ( w , id , s . Logger )
2016-11-03 06:42:52 +00:00
return
}
2016-11-04 00:44:28 +00:00
2017-10-20 03:48:31 +00:00
c := kapa . NewClient ( srv . URL , srv . Username , srv . Password , srv . InsecureSkipVerify )
2017-07-25 14:57:46 +00:00
tasks , err := c . All ( ctx )
2017-02-10 19:48:42 +00:00
if err != nil {
2017-10-10 22:27:58 +00:00
Error ( w , http . StatusInternalServerError , err . Error ( ) , s . Logger )
2017-02-10 19:48:42 +00:00
return
}
2016-11-04 00:44:28 +00:00
res := allAlertsResponse {
2017-07-25 14:57:46 +00:00
Rules : [ ] * alertResponse { } ,
2016-11-04 00:44:28 +00:00
}
2017-07-25 14:57:46 +00:00
for _ , task := range tasks {
ar := newAlertResponse ( task , srv . SrcID , srv . ID )
2016-11-04 06:53:54 +00:00
res . Rules = append ( res . Rules , ar )
2016-11-04 00:44:28 +00:00
}
2017-10-10 22:27:58 +00:00
encodeJSON ( w , http . StatusOK , res , s . Logger )
2016-11-04 00:44:28 +00:00
}
type allAlertsResponse struct {
2017-07-25 14:57:46 +00:00
Rules [ ] * alertResponse ` json:"rules" `
2016-11-03 06:42:52 +00:00
}
2016-11-19 17:41:06 +00:00
// KapacitorRulesID retrieves specific task
2017-10-10 22:27:58 +00:00
func ( s * Service ) KapacitorRulesID ( w http . ResponseWriter , r * http . Request ) {
2016-11-03 06:42:52 +00:00
id , err := paramID ( "kid" , r )
if err != nil {
2017-10-10 22:27:58 +00:00
Error ( w , http . StatusUnprocessableEntity , err . Error ( ) , s . Logger )
2016-11-03 06:42:52 +00:00
return
}
srcID , err := paramID ( "id" , r )
if err != nil {
2017-10-10 22:27:58 +00:00
Error ( w , http . StatusUnprocessableEntity , err . Error ( ) , s . Logger )
2016-11-03 06:42:52 +00:00
return
}
ctx := r . Context ( )
2017-10-31 20:41:17 +00:00
srv , err := s . Store . Servers ( ctx ) . Get ( ctx , id )
2016-11-03 06:42:52 +00:00
if err != nil || srv . SrcID != srcID {
2017-10-10 22:27:58 +00:00
notFound ( w , id , s . Logger )
2016-11-03 06:42:52 +00:00
return
}
tid := httprouter . GetParamFromContext ( ctx , "tid" )
2016-11-04 00:44:28 +00:00
2017-10-20 03:48:31 +00:00
c := kapa . NewClient ( srv . URL , srv . Username , srv . Password , srv . InsecureSkipVerify )
2017-04-06 01:04:42 +00:00
// Check if the rule exists within scope
2017-07-25 14:57:46 +00:00
task , err := c . Get ( ctx , tid )
2016-11-04 00:44:28 +00:00
if err != nil {
2017-04-06 01:04:42 +00:00
if err == chronograf . ErrAlertNotFound {
2017-10-10 22:27:58 +00:00
notFound ( w , id , s . Logger )
2017-04-06 01:04:42 +00:00
return
}
2017-10-10 22:27:58 +00:00
Error ( w , http . StatusInternalServerError , err . Error ( ) , s . Logger )
2016-11-04 00:44:28 +00:00
return
}
2017-02-10 19:48:42 +00:00
2017-07-25 14:57:46 +00:00
res := newAlertResponse ( task , srv . SrcID , srv . ID )
2017-10-10 22:27:58 +00:00
encodeJSON ( w , http . StatusOK , res , s . Logger )
2016-10-31 23:11:05 +00:00
}
2016-11-19 17:41:06 +00:00
// KapacitorRulesDelete proxies DELETE to kapacitor
2017-10-10 22:27:58 +00:00
func ( s * Service ) KapacitorRulesDelete ( w http . ResponseWriter , r * http . Request ) {
2016-11-03 06:42:52 +00:00
id , err := paramID ( "kid" , r )
if err != nil {
2017-10-10 22:27:58 +00:00
Error ( w , http . StatusUnprocessableEntity , err . Error ( ) , s . Logger )
2016-11-03 06:42:52 +00:00
return
}
srcID , err := paramID ( "id" , r )
if err != nil {
2017-10-10 22:27:58 +00:00
Error ( w , http . StatusUnprocessableEntity , err . Error ( ) , s . Logger )
2016-11-03 06:42:52 +00:00
return
}
ctx := r . Context ( )
2017-10-31 20:41:17 +00:00
srv , err := s . Store . Servers ( ctx ) . Get ( ctx , id )
2016-11-03 06:42:52 +00:00
if err != nil || srv . SrcID != srcID {
2017-10-10 22:27:58 +00:00
notFound ( w , id , s . Logger )
2016-11-03 06:42:52 +00:00
return
}
2017-10-20 03:48:31 +00:00
c := kapa . NewClient ( srv . URL , srv . Username , srv . Password , srv . InsecureSkipVerify )
2016-11-04 01:56:42 +00:00
2017-04-06 01:04:42 +00:00
tid := httprouter . GetParamFromContext ( ctx , "tid" )
2016-11-04 01:56:42 +00:00
// Check if the rule is linked to this server and kapacitor
2017-04-06 01:04:42 +00:00
if _ , err := c . Get ( ctx , tid ) ; err != nil {
2016-11-04 01:56:42 +00:00
if err == chronograf . ErrAlertNotFound {
2017-10-10 22:27:58 +00:00
notFound ( w , id , s . Logger )
2016-11-04 01:56:42 +00:00
return
}
2017-10-10 22:27:58 +00:00
Error ( w , http . StatusInternalServerError , err . Error ( ) , s . Logger )
2016-11-04 01:56:42 +00:00
return
}
2016-11-03 06:42:52 +00:00
if err := c . Delete ( ctx , c . Href ( tid ) ) ; err != nil {
2017-10-10 22:27:58 +00:00
Error ( w , http . StatusInternalServerError , err . Error ( ) , s . Logger )
2016-11-03 06:42:52 +00:00
return
}
2016-11-04 00:44:28 +00:00
2016-11-03 06:42:52 +00:00
w . WriteHeader ( http . StatusNoContent )
2016-10-31 23:11:05 +00:00
}