2019-07-24 21:53:53 +00:00
package http
import (
"bytes"
"context"
"encoding/json"
"fmt"
"net/http"
2020-03-05 00:32:33 +00:00
"path"
2019-12-27 18:14:34 +00:00
"time"
2019-07-24 21:53:53 +00:00
2019-11-25 14:22:19 +00:00
"github.com/influxdata/httprouter"
2020-04-03 17:39:20 +00:00
"github.com/influxdata/influxdb/v2"
pctx "github.com/influxdata/influxdb/v2/context"
"github.com/influxdata/influxdb/v2/notification/rule"
"github.com/influxdata/influxdb/v2/pkg/httpc"
2019-07-24 21:53:53 +00:00
"go.uber.org/zap"
)
2020-03-05 00:32:33 +00:00
var _ influxdb . NotificationRuleStore = ( * NotificationRuleService ) ( nil )
2019-09-18 20:19:51 +00:00
type statusDecode struct {
Status * influxdb . Status ` json:"status" `
}
2019-07-24 21:53:53 +00:00
// NotificationRuleBackend is all services and associated parameters required to construct
// the NotificationRuleBackendHandler.
type NotificationRuleBackend struct {
influxdb . HTTPErrorHandler
2019-12-04 23:10:23 +00:00
log * zap . Logger
2019-07-24 21:53:53 +00:00
2019-08-23 15:09:34 +00:00
NotificationRuleStore influxdb . NotificationRuleStore
NotificationEndpointService influxdb . NotificationEndpointService
UserResourceMappingService influxdb . UserResourceMappingService
LabelService influxdb . LabelService
UserService influxdb . UserService
OrganizationService influxdb . OrganizationService
2019-09-18 20:19:51 +00:00
TaskService influxdb . TaskService
2019-07-24 21:53:53 +00:00
}
// NewNotificationRuleBackend returns a new instance of NotificationRuleBackend.
2019-12-04 23:10:23 +00:00
func NewNotificationRuleBackend ( log * zap . Logger , b * APIBackend ) * NotificationRuleBackend {
2019-07-24 21:53:53 +00:00
return & NotificationRuleBackend {
HTTPErrorHandler : b . HTTPErrorHandler ,
2019-12-04 23:10:23 +00:00
log : log ,
2019-07-24 21:53:53 +00:00
2019-08-23 15:09:34 +00:00
NotificationRuleStore : b . NotificationRuleStore ,
NotificationEndpointService : b . NotificationEndpointService ,
UserResourceMappingService : b . UserResourceMappingService ,
LabelService : b . LabelService ,
UserService : b . UserService ,
OrganizationService : b . OrganizationService ,
2019-09-18 20:19:51 +00:00
TaskService : b . TaskService ,
2019-07-24 21:53:53 +00:00
}
}
// NotificationRuleHandler is the handler for the notification rule service
type NotificationRuleHandler struct {
* httprouter . Router
influxdb . HTTPErrorHandler
2019-12-04 23:10:23 +00:00
log * zap . Logger
2019-07-24 21:53:53 +00:00
2019-08-23 15:09:34 +00:00
NotificationRuleStore influxdb . NotificationRuleStore
NotificationEndpointService influxdb . NotificationEndpointService
UserResourceMappingService influxdb . UserResourceMappingService
LabelService influxdb . LabelService
UserService influxdb . UserService
OrganizationService influxdb . OrganizationService
2019-09-18 20:19:51 +00:00
TaskService influxdb . TaskService
2019-07-24 21:53:53 +00:00
}
const (
2019-12-09 23:54:16 +00:00
prefixNotificationRules = "/api/v2/notificationRules"
2019-07-24 21:53:53 +00:00
notificationRulesIDPath = "/api/v2/notificationRules/:id"
2019-08-23 15:09:34 +00:00
notificationRulesIDQueryPath = "/api/v2/notificationRules/:id/query"
2019-07-24 21:53:53 +00:00
notificationRulesIDMembersPath = "/api/v2/notificationRules/:id/members"
notificationRulesIDMembersIDPath = "/api/v2/notificationRules/:id/members/:userID"
notificationRulesIDOwnersPath = "/api/v2/notificationRules/:id/owners"
notificationRulesIDOwnersIDPath = "/api/v2/notificationRules/:id/owners/:userID"
notificationRulesIDLabelsPath = "/api/v2/notificationRules/:id/labels"
notificationRulesIDLabelsIDPath = "/api/v2/notificationRules/:id/labels/:lid"
)
// NewNotificationRuleHandler returns a new instance of NotificationRuleHandler.
2019-12-04 23:10:23 +00:00
func NewNotificationRuleHandler ( log * zap . Logger , b * NotificationRuleBackend ) * NotificationRuleHandler {
2019-07-24 21:53:53 +00:00
h := & NotificationRuleHandler {
Router : NewRouter ( b . HTTPErrorHandler ) ,
HTTPErrorHandler : b . HTTPErrorHandler ,
2019-12-04 23:10:23 +00:00
log : log ,
2019-07-24 21:53:53 +00:00
2019-08-23 15:09:34 +00:00
NotificationRuleStore : b . NotificationRuleStore ,
NotificationEndpointService : b . NotificationEndpointService ,
UserResourceMappingService : b . UserResourceMappingService ,
LabelService : b . LabelService ,
UserService : b . UserService ,
OrganizationService : b . OrganizationService ,
2019-09-18 20:19:51 +00:00
TaskService : b . TaskService ,
2019-07-24 21:53:53 +00:00
}
2019-12-09 23:54:16 +00:00
h . HandlerFunc ( "POST" , prefixNotificationRules , h . handlePostNotificationRule )
h . HandlerFunc ( "GET" , prefixNotificationRules , h . handleGetNotificationRules )
2019-07-24 21:53:53 +00:00
h . HandlerFunc ( "GET" , notificationRulesIDPath , h . handleGetNotificationRule )
2019-08-23 15:09:34 +00:00
h . HandlerFunc ( "GET" , notificationRulesIDQueryPath , h . handleGetNotificationRuleQuery )
2019-07-24 21:53:53 +00:00
h . HandlerFunc ( "DELETE" , notificationRulesIDPath , h . handleDeleteNotificationRule )
h . HandlerFunc ( "PUT" , notificationRulesIDPath , h . handlePutNotificationRule )
2019-07-28 14:08:12 +00:00
h . HandlerFunc ( "PATCH" , notificationRulesIDPath , h . handlePatchNotificationRule )
2019-07-24 21:53:53 +00:00
memberBackend := MemberBackend {
HTTPErrorHandler : b . HTTPErrorHandler ,
2019-12-04 23:10:23 +00:00
log : b . log . With ( zap . String ( "handler" , "member" ) ) ,
2019-07-24 21:53:53 +00:00
ResourceType : influxdb . NotificationRuleResourceType ,
UserType : influxdb . Member ,
UserResourceMappingService : b . UserResourceMappingService ,
UserService : b . UserService ,
}
h . HandlerFunc ( "POST" , notificationRulesIDMembersPath , newPostMemberHandler ( memberBackend ) )
h . HandlerFunc ( "GET" , notificationRulesIDMembersPath , newGetMembersHandler ( memberBackend ) )
h . HandlerFunc ( "DELETE" , notificationRulesIDMembersIDPath , newDeleteMemberHandler ( memberBackend ) )
ownerBackend := MemberBackend {
HTTPErrorHandler : b . HTTPErrorHandler ,
2019-12-04 23:10:23 +00:00
log : b . log . With ( zap . String ( "handler" , "member" ) ) ,
2019-07-24 21:53:53 +00:00
ResourceType : influxdb . NotificationRuleResourceType ,
UserType : influxdb . Owner ,
UserResourceMappingService : b . UserResourceMappingService ,
UserService : b . UserService ,
}
h . HandlerFunc ( "POST" , notificationRulesIDOwnersPath , newPostMemberHandler ( ownerBackend ) )
h . HandlerFunc ( "GET" , notificationRulesIDOwnersPath , newGetMembersHandler ( ownerBackend ) )
h . HandlerFunc ( "DELETE" , notificationRulesIDOwnersIDPath , newDeleteMemberHandler ( ownerBackend ) )
labelBackend := & LabelBackend {
HTTPErrorHandler : b . HTTPErrorHandler ,
2019-12-04 23:10:23 +00:00
log : b . log . With ( zap . String ( "handler" , "label" ) ) ,
2019-07-24 21:53:53 +00:00
LabelService : b . LabelService ,
2020-03-16 10:32:35 +00:00
ResourceType : influxdb . NotificationRuleResourceType ,
2019-07-24 21:53:53 +00:00
}
2019-10-07 07:36:55 +00:00
h . HandlerFunc ( "GET" , notificationRulesIDLabelsPath , newGetLabelsHandler ( labelBackend ) )
2019-07-24 21:53:53 +00:00
h . HandlerFunc ( "POST" , notificationRulesIDLabelsPath , newPostLabelHandler ( labelBackend ) )
h . HandlerFunc ( "DELETE" , notificationRulesIDLabelsIDPath , newDeleteLabelHandler ( labelBackend ) )
return h
}
type notificationRuleLinks struct {
Self string ` json:"self" `
Labels string ` json:"labels" `
Members string ` json:"members" `
Owners string ` json:"owners" `
2019-11-08 16:23:38 +00:00
Query string ` json:"query" `
2019-07-24 21:53:53 +00:00
}
type notificationRuleResponse struct {
influxdb . NotificationRule
2019-12-27 18:14:34 +00:00
Labels [ ] influxdb . Label ` json:"labels" `
Links notificationRuleLinks ` json:"links" `
Status string ` json:"status" `
LatestCompleted time . Time ` json:"latestCompleted,omitempty" `
LatestScheduled time . Time ` json:"latestScheduled,omitempty" `
LastRunStatus string ` json:"LastRunStatus,omitempty" `
LastRunError string ` json:"LastRunError,omitempty" `
2019-07-24 21:53:53 +00:00
}
func ( resp notificationRuleResponse ) MarshalJSON ( ) ( [ ] byte , error ) {
b1 , err := json . Marshal ( resp . NotificationRule )
if err != nil {
return nil , err
}
b2 , err := json . Marshal ( struct {
2019-12-27 18:14:34 +00:00
Labels [ ] influxdb . Label ` json:"labels" `
Links notificationRuleLinks ` json:"links" `
Status string ` json:"status" `
LatestCompleted time . Time ` json:"latestCompleted,omitempty" `
LatestScheduled time . Time ` json:"latestScheduled,omitempty" `
LastRunStatus string ` json:"lastRunStatus,omitempty" `
LastRunError string ` json:"lastRunError,omitempty" `
2019-07-24 21:53:53 +00:00
} {
2019-12-27 18:14:34 +00:00
Links : resp . Links ,
Labels : resp . Labels ,
Status : resp . Status ,
LatestCompleted : resp . LatestCompleted ,
LatestScheduled : resp . LatestScheduled ,
LastRunStatus : resp . LastRunStatus ,
LastRunError : resp . LastRunError ,
2019-07-24 21:53:53 +00:00
} )
if err != nil {
return nil , err
}
return [ ] byte ( string ( b1 [ : len ( b1 ) - 1 ] ) + ", " + string ( b2 [ 1 : ] ) ) , nil
}
type notificationRulesResponse struct {
NotificationRules [ ] * notificationRuleResponse ` json:"notificationRules" `
Links * influxdb . PagingLinks ` json:"links" `
}
2019-09-18 20:19:51 +00:00
func ( h * NotificationRuleHandler ) newNotificationRuleResponse ( ctx context . Context , nr influxdb . NotificationRule , labels [ ] * influxdb . Label ) ( * notificationRuleResponse , error ) {
2019-09-25 20:33:05 +00:00
// TODO(desa): this should be handled in the rule service and not exposed in http land, but is currently blocking the FE. https://github.com/influxdata/influxdb/issues/15259
t , err := h . TaskService . FindTaskByID ( ctx , nr . GetTaskID ( ) )
if err != nil {
return nil , err
}
2019-08-16 19:43:15 +00:00
nr . ClearPrivateData ( )
2019-07-24 21:53:53 +00:00
res := & notificationRuleResponse {
NotificationRule : nr ,
Links : notificationRuleLinks {
Self : fmt . Sprintf ( "/api/v2/notificationRules/%s" , nr . GetID ( ) ) ,
Labels : fmt . Sprintf ( "/api/v2/notificationRules/%s/labels" , nr . GetID ( ) ) ,
Members : fmt . Sprintf ( "/api/v2/notificationRules/%s/members" , nr . GetID ( ) ) ,
Owners : fmt . Sprintf ( "/api/v2/notificationRules/%s/owners" , nr . GetID ( ) ) ,
2019-11-08 16:23:38 +00:00
Query : fmt . Sprintf ( "/api/v2/notificationRules/%s/query" , nr . GetID ( ) ) ,
2019-07-24 21:53:53 +00:00
} ,
2019-12-27 18:14:34 +00:00
Labels : [ ] influxdb . Label { } ,
Status : t . Status ,
LatestCompleted : t . LatestCompleted ,
LatestScheduled : t . LatestScheduled ,
LastRunStatus : t . LastRunStatus ,
LastRunError : t . LastRunError ,
2019-07-24 21:53:53 +00:00
}
for _ , l := range labels {
res . Labels = append ( res . Labels , * l )
}
2019-09-18 20:19:51 +00:00
return res , nil
2019-07-24 21:53:53 +00:00
}
2019-09-18 20:19:51 +00:00
func ( h * NotificationRuleHandler ) newNotificationRulesResponse ( ctx context . Context , nrs [ ] influxdb . NotificationRule , labelService influxdb . LabelService , f influxdb . PagingFilter , opts influxdb . FindOptions ) ( * notificationRulesResponse , error ) {
2019-07-24 21:53:53 +00:00
resp := & notificationRulesResponse {
2019-09-18 20:19:51 +00:00
NotificationRules : [ ] * notificationRuleResponse { } ,
2020-04-30 14:52:21 +00:00
Links : influxdb . NewPagingLinks ( prefixNotificationRules , opts , f , len ( nrs ) ) ,
2019-07-24 21:53:53 +00:00
}
2019-09-18 20:19:51 +00:00
for _ , nr := range nrs {
2020-03-12 17:51:50 +00:00
labels , _ := labelService . FindResourceLabels ( ctx , influxdb . LabelMappingFilter { ResourceID : nr . GetID ( ) , ResourceType : influxdb . NotificationRuleResourceType } )
2019-09-18 20:19:51 +00:00
res , err := h . newNotificationRuleResponse ( ctx , nr , labels )
if err != nil {
continue
}
resp . NotificationRules = append ( resp . NotificationRules , res )
2019-07-24 21:53:53 +00:00
}
2019-09-18 20:19:51 +00:00
return resp , nil
2019-07-24 21:53:53 +00:00
}
func decodeGetNotificationRuleRequest ( ctx context . Context , r * http . Request ) ( i influxdb . ID , err error ) {
params := httprouter . ParamsFromContext ( ctx )
id := params . ByName ( "id" )
if id == "" {
return i , & influxdb . Error {
Code : influxdb . EInvalid ,
Msg : "url missing id" ,
}
}
if err := i . DecodeFromString ( id ) ; err != nil {
return i , err
}
return i , nil
}
func ( h * NotificationRuleHandler ) handleGetNotificationRules ( w http . ResponseWriter , r * http . Request ) {
ctx := r . Context ( )
filter , opts , err := decodeNotificationRuleFilter ( ctx , r )
if err != nil {
2019-12-04 23:10:23 +00:00
h . log . Debug ( "Failed to decode request" , zap . Error ( err ) )
2019-07-24 21:53:53 +00:00
h . HandleHTTPError ( ctx , err , w )
return
}
nrs , _ , err := h . NotificationRuleStore . FindNotificationRules ( ctx , * filter , * opts )
if err != nil {
h . HandleHTTPError ( ctx , err , w )
return
}
2019-12-04 23:10:23 +00:00
h . log . Debug ( "Notification rules retrieved" , zap . String ( "notificationRules" , fmt . Sprint ( nrs ) ) )
2019-07-24 21:53:53 +00:00
2019-09-18 20:19:51 +00:00
res , err := h . newNotificationRulesResponse ( ctx , nrs , h . LabelService , filter , * opts )
if err != nil {
h . HandleHTTPError ( ctx , err , w )
return
}
if err := encodeResponse ( ctx , w , http . StatusOK , res ) ; err != nil {
2019-12-04 23:10:23 +00:00
logEncodingError ( h . log , r , err )
2019-07-24 21:53:53 +00:00
return
}
}
2019-08-23 15:09:34 +00:00
func ( h * NotificationRuleHandler ) handleGetNotificationRuleQuery ( w http . ResponseWriter , r * http . Request ) {
ctx := r . Context ( )
id , err := decodeGetNotificationRuleRequest ( ctx , r )
if err != nil {
h . HandleHTTPError ( ctx , err , w )
return
}
nr , err := h . NotificationRuleStore . FindNotificationRuleByID ( ctx , id )
if err != nil {
h . HandleHTTPError ( ctx , err , w )
return
}
edp , err := h . NotificationEndpointService . FindNotificationEndpointByID ( ctx , nr . GetEndpointID ( ) )
if err != nil {
h . HandleHTTPError ( ctx , & influxdb . Error {
Code : influxdb . EInternal ,
Op : "http/handleGetNotificationRuleQuery" ,
Err : err ,
} , w )
return
}
flux , err := nr . GenerateFlux ( edp )
if err != nil {
h . HandleHTTPError ( ctx , err , w )
return
}
2019-12-04 23:10:23 +00:00
h . log . Debug ( "Notification rule query retrieved" , zap . String ( "notificationRuleQuery" , fmt . Sprint ( flux ) ) )
2019-08-23 15:09:34 +00:00
if err := encodeResponse ( ctx , w , http . StatusOK , newFluxResponse ( flux ) ) ; err != nil {
2019-12-04 23:10:23 +00:00
logEncodingError ( h . log , r , err )
2019-08-23 15:09:34 +00:00
return
}
}
2019-07-24 21:53:53 +00:00
func ( h * NotificationRuleHandler ) handleGetNotificationRule ( w http . ResponseWriter , r * http . Request ) {
ctx := r . Context ( )
id , err := decodeGetNotificationRuleRequest ( ctx , r )
if err != nil {
h . HandleHTTPError ( ctx , err , w )
return
}
nr , err := h . NotificationRuleStore . FindNotificationRuleByID ( ctx , id )
if err != nil {
h . HandleHTTPError ( ctx , err , w )
return
}
2019-12-04 23:10:23 +00:00
h . log . Debug ( "Notification rule retrieved" , zap . String ( "notificationRule" , fmt . Sprint ( nr ) ) )
2019-07-24 21:53:53 +00:00
2020-03-12 17:51:50 +00:00
labels , err := h . LabelService . FindResourceLabels ( ctx , influxdb . LabelMappingFilter { ResourceID : nr . GetID ( ) , ResourceType : influxdb . NotificationRuleResourceType } )
2019-07-24 21:53:53 +00:00
if err != nil {
h . HandleHTTPError ( ctx , err , w )
return
}
2019-09-18 20:19:51 +00:00
res , err := h . newNotificationRuleResponse ( ctx , nr , labels )
if err != nil {
h . HandleHTTPError ( ctx , err , w )
return
}
if err := encodeResponse ( ctx , w , http . StatusOK , res ) ; err != nil {
2019-12-04 23:10:23 +00:00
logEncodingError ( h . log , r , err )
2019-07-24 21:53:53 +00:00
return
}
}
func decodeNotificationRuleFilter ( ctx context . Context , r * http . Request ) ( * influxdb . NotificationRuleFilter , * influxdb . FindOptions , error ) {
f := & influxdb . NotificationRuleFilter { }
urm , err := decodeUserResourceMappingFilter ( ctx , r , influxdb . NotificationRuleResourceType )
if err == nil {
f . UserResourceMappingFilter = * urm
}
2020-04-30 14:52:21 +00:00
opts , err := influxdb . DecodeFindOptions ( r )
2019-07-24 21:53:53 +00:00
if err != nil {
return f , nil , err
}
q := r . URL . Query ( )
if orgIDStr := q . Get ( "orgID" ) ; orgIDStr != "" {
orgID , err := influxdb . IDFromString ( orgIDStr )
if err != nil {
return f , opts , & influxdb . Error {
Code : influxdb . EInvalid ,
Msg : "orgID is invalid" ,
Err : err ,
}
}
f . OrgID = orgID
} else if orgNameStr := q . Get ( "org" ) ; orgNameStr != "" {
* f . Organization = orgNameStr
}
2019-08-28 16:25:54 +00:00
for _ , tag := range q [ "tag" ] {
tp , err := influxdb . NewTag ( tag )
// ignore malformed tag pairs
if err == nil {
f . Tags = append ( f . Tags , tp )
}
}
2019-07-24 21:53:53 +00:00
return f , opts , err
}
func decodeUserResourceMappingFilter ( ctx context . Context , r * http . Request , typ influxdb . ResourceType ) ( * influxdb . UserResourceMappingFilter , error ) {
q := r . URL . Query ( )
f := & influxdb . UserResourceMappingFilter {
ResourceType : typ ,
}
if idStr := q . Get ( "resourceID" ) ; idStr != "" {
id , err := influxdb . IDFromString ( idStr )
if err != nil {
return nil , err
}
f . ResourceID = * id
}
if idStr := q . Get ( "userID" ) ; idStr != "" {
id , err := influxdb . IDFromString ( idStr )
if err != nil {
return nil , err
}
f . UserID = * id
}
return f , nil
}
2019-09-30 23:15:14 +00:00
type postNotificationRuleRequest struct {
influxdb . NotificationRuleCreate
Labels [ ] string ` json:"labels" `
}
func decodePostNotificationRuleRequest ( ctx context . Context , r * http . Request ) ( postNotificationRuleRequest , error ) {
var pnrr postNotificationRuleRequest
2019-09-18 20:19:51 +00:00
var sts statusDecode
2019-09-30 23:15:14 +00:00
var dl decodeLabels
2019-09-18 20:19:51 +00:00
2019-07-24 21:53:53 +00:00
buf := new ( bytes . Buffer )
_ , err := buf . ReadFrom ( r . Body )
if err != nil {
2019-09-30 23:15:14 +00:00
return pnrr , & influxdb . Error {
2019-07-24 21:53:53 +00:00
Code : influxdb . EInvalid ,
Err : err ,
}
}
defer r . Body . Close ( )
2019-09-30 23:15:14 +00:00
2019-07-24 21:53:53 +00:00
nr , err := rule . UnmarshalJSON ( buf . Bytes ( ) )
if err != nil {
2019-09-30 23:15:14 +00:00
return pnrr , & influxdb . Error {
2019-07-24 21:53:53 +00:00
Code : influxdb . EInvalid ,
Err : err ,
}
}
2019-09-18 20:19:51 +00:00
if err := json . Unmarshal ( buf . Bytes ( ) , & sts ) ; err != nil {
2019-09-30 23:15:14 +00:00
return pnrr , err
2019-09-18 20:19:51 +00:00
}
2019-09-30 23:15:14 +00:00
if err := json . Unmarshal ( buf . Bytes ( ) , & dl ) ; err != nil {
return pnrr , err
2019-09-18 20:19:51 +00:00
}
2019-09-30 23:15:14 +00:00
pnrr = postNotificationRuleRequest {
NotificationRuleCreate : influxdb . NotificationRuleCreate {
NotificationRule : nr ,
Status : * sts . Status ,
} ,
Labels : dl . Labels ,
}
return pnrr , nil
2019-07-24 21:53:53 +00:00
}
2019-09-18 20:19:51 +00:00
func decodePutNotificationRuleRequest ( ctx context . Context , r * http . Request ) ( influxdb . NotificationRuleCreate , error ) {
var nrc influxdb . NotificationRuleCreate
var sts statusDecode
2019-07-24 21:53:53 +00:00
buf := new ( bytes . Buffer )
_ , err := buf . ReadFrom ( r . Body )
if err != nil {
2019-09-18 20:19:51 +00:00
return nrc , & influxdb . Error {
2019-07-24 21:53:53 +00:00
Code : influxdb . EInvalid ,
Err : err ,
}
}
defer r . Body . Close ( )
nr , err := rule . UnmarshalJSON ( buf . Bytes ( ) )
if err != nil {
2019-09-18 20:19:51 +00:00
return nrc , & influxdb . Error {
2019-07-24 21:53:53 +00:00
Code : influxdb . EInvalid ,
Err : err ,
}
}
params := httprouter . ParamsFromContext ( ctx )
id := params . ByName ( "id" )
if id == "" {
2019-09-18 20:19:51 +00:00
return nrc , & influxdb . Error {
2019-07-24 21:53:53 +00:00
Code : influxdb . EInvalid ,
Msg : "url missing id" ,
}
}
i := new ( influxdb . ID )
if err := i . DecodeFromString ( id ) ; err != nil {
2019-09-18 20:19:51 +00:00
return nrc , err
2019-07-24 21:53:53 +00:00
}
nr . SetID ( * i )
2019-09-18 20:19:51 +00:00
err = json . Unmarshal ( buf . Bytes ( ) , & sts )
if err != nil {
return nrc , err
}
nrc = influxdb . NotificationRuleCreate {
NotificationRule : nr ,
Status : * sts . Status ,
}
return nrc , nil
2019-07-24 21:53:53 +00:00
}
2019-07-28 14:08:12 +00:00
type patchNotificationRuleRequest struct {
influxdb . ID
Update influxdb . NotificationRuleUpdate
}
func decodePatchNotificationRuleRequest ( ctx context . Context , r * http . Request ) ( * patchNotificationRuleRequest , error ) {
req := & patchNotificationRuleRequest { }
params := httprouter . ParamsFromContext ( ctx )
id := params . ByName ( "id" )
if id == "" {
return nil , & influxdb . Error {
Code : influxdb . EInvalid ,
Msg : "url missing id" ,
}
}
var i influxdb . ID
if err := i . DecodeFromString ( id ) ; err != nil {
return nil , err
}
req . ID = i
upd := & influxdb . NotificationRuleUpdate { }
if err := json . NewDecoder ( r . Body ) . Decode ( upd ) ; err != nil {
return nil , & influxdb . Error {
Code : influxdb . EInvalid ,
Msg : err . Error ( ) ,
}
}
if err := upd . Valid ( ) ; err != nil {
return nil , & influxdb . Error {
Code : influxdb . EInvalid ,
Msg : err . Error ( ) ,
}
}
req . Update = * upd
return req , nil
}
2019-07-24 21:53:53 +00:00
// handlePostNotificationRule is the HTTP handler for the POST /api/v2/notificationRules route.
func ( h * NotificationRuleHandler ) handlePostNotificationRule ( w http . ResponseWriter , r * http . Request ) {
ctx := r . Context ( )
nr , err := decodePostNotificationRuleRequest ( ctx , r )
if err != nil {
2019-12-04 23:10:23 +00:00
h . log . Debug ( "Failed to decode request" , zap . Error ( err ) )
2019-07-24 21:53:53 +00:00
h . HandleHTTPError ( ctx , err , w )
return
}
2019-08-19 22:56:17 +00:00
2019-07-24 21:53:53 +00:00
auth , err := pctx . GetAuthorizer ( ctx )
if err != nil {
h . HandleHTTPError ( ctx , err , w )
return
}
2019-09-30 23:15:14 +00:00
if err := h . NotificationRuleStore . CreateNotificationRule ( ctx , nr . NotificationRuleCreate , auth . GetUserID ( ) ) ; err != nil {
2019-07-24 21:53:53 +00:00
h . HandleHTTPError ( ctx , err , w )
return
}
2019-12-04 23:10:23 +00:00
h . log . Debug ( "Notification rule created" , zap . String ( "notificationRule" , fmt . Sprint ( nr ) ) )
2019-07-24 21:53:53 +00:00
2019-09-30 23:15:14 +00:00
labels := h . mapNewNotificationRuleLabels ( ctx , nr . NotificationRuleCreate , nr . Labels )
res , err := h . newNotificationRuleResponse ( ctx , nr , labels )
2019-09-18 20:19:51 +00:00
if err != nil {
h . HandleHTTPError ( ctx , err , w )
return
}
if err := encodeResponse ( ctx , w , http . StatusCreated , res ) ; err != nil {
2019-12-04 23:10:23 +00:00
logEncodingError ( h . log , r , err )
2019-07-24 21:53:53 +00:00
return
}
}
2019-09-30 23:15:14 +00:00
func ( h * NotificationRuleHandler ) mapNewNotificationRuleLabels ( ctx context . Context , nrc influxdb . NotificationRuleCreate , labels [ ] string ) [ ] * influxdb . Label {
var ls [ ] * influxdb . Label
for _ , sid := range labels {
var lid influxdb . ID
err := lid . DecodeFromString ( sid )
if err != nil {
continue
}
label , err := h . LabelService . FindLabelByID ( ctx , lid )
if err != nil {
continue
}
mapping := influxdb . LabelMapping {
LabelID : label . ID ,
ResourceID : nrc . GetID ( ) ,
ResourceType : influxdb . NotificationRuleResourceType ,
}
err = h . LabelService . CreateLabelMapping ( ctx , & mapping )
if err != nil {
continue
}
ls = append ( ls , label )
}
return ls
}
2019-07-24 21:53:53 +00:00
// handlePutNotificationRule is the HTTP handler for the PUT /api/v2/notificationRule route.
func ( h * NotificationRuleHandler ) handlePutNotificationRule ( w http . ResponseWriter , r * http . Request ) {
ctx := r . Context ( )
2019-09-18 20:19:51 +00:00
nrc , err := decodePutNotificationRuleRequest ( ctx , r )
2019-07-24 21:53:53 +00:00
if err != nil {
2019-12-04 23:10:23 +00:00
h . log . Debug ( "Failed to decode request" , zap . Error ( err ) )
2019-07-24 21:53:53 +00:00
h . HandleHTTPError ( ctx , err , w )
return
}
auth , err := pctx . GetAuthorizer ( ctx )
if err != nil {
h . HandleHTTPError ( ctx , err , w )
return
}
2019-09-18 20:19:51 +00:00
nr , err := h . NotificationRuleStore . UpdateNotificationRule ( ctx , nrc . GetID ( ) , nrc , auth . GetUserID ( ) )
2019-07-24 21:53:53 +00:00
if err != nil {
h . HandleHTTPError ( ctx , err , w )
return
}
2020-03-12 17:51:50 +00:00
labels , err := h . LabelService . FindResourceLabels ( ctx , influxdb . LabelMappingFilter { ResourceID : nr . GetID ( ) , ResourceType : influxdb . NotificationRuleResourceType } )
2019-07-24 21:53:53 +00:00
if err != nil {
h . HandleHTTPError ( ctx , err , w )
return
}
2019-12-04 23:10:23 +00:00
h . log . Debug ( "Notification rule updated" , zap . String ( "notificationRule" , fmt . Sprint ( nr ) ) )
2019-07-24 21:53:53 +00:00
2019-09-18 20:19:51 +00:00
res , err := h . newNotificationRuleResponse ( ctx , nr , labels )
if err != nil {
h . HandleHTTPError ( ctx , err , w )
return
}
if err := encodeResponse ( ctx , w , http . StatusOK , res ) ; err != nil {
2019-12-04 23:10:23 +00:00
logEncodingError ( h . log , r , err )
2019-07-24 21:53:53 +00:00
return
}
}
2019-07-28 14:08:12 +00:00
// handlePatchNotificationRule is the HTTP handler for the PATCH /api/v2/notificationRule/:id route.
func ( h * NotificationRuleHandler ) handlePatchNotificationRule ( w http . ResponseWriter , r * http . Request ) {
ctx := r . Context ( )
req , err := decodePatchNotificationRuleRequest ( ctx , r )
if err != nil {
2019-12-04 23:10:23 +00:00
h . log . Debug ( "Failed to decode request" , zap . Error ( err ) )
2019-07-28 14:08:12 +00:00
h . HandleHTTPError ( ctx , err , w )
return
}
nr , err := h . NotificationRuleStore . PatchNotificationRule ( ctx , req . ID , req . Update )
if err != nil {
h . HandleHTTPError ( ctx , err , w )
return
}
2020-03-12 17:51:50 +00:00
labels , err := h . LabelService . FindResourceLabels ( ctx , influxdb . LabelMappingFilter { ResourceID : nr . GetID ( ) , ResourceType : influxdb . NotificationRuleResourceType } )
2019-07-28 14:08:12 +00:00
if err != nil {
h . HandleHTTPError ( ctx , err , w )
return
}
2019-12-04 23:10:23 +00:00
h . log . Debug ( "Notification rule patch" , zap . String ( "notificationRule" , fmt . Sprint ( nr ) ) )
2019-07-28 14:08:12 +00:00
2019-09-18 20:19:51 +00:00
res , err := h . newNotificationRuleResponse ( ctx , nr , labels )
if err != nil {
h . HandleHTTPError ( ctx , err , w )
return
}
if err := encodeResponse ( ctx , w , http . StatusOK , res ) ; err != nil {
2019-12-04 23:10:23 +00:00
logEncodingError ( h . log , r , err )
2019-07-28 14:08:12 +00:00
return
}
}
2019-07-24 21:53:53 +00:00
func ( h * NotificationRuleHandler ) handleDeleteNotificationRule ( w http . ResponseWriter , r * http . Request ) {
ctx := r . Context ( )
i , err := decodeGetNotificationRuleRequest ( ctx , r )
if err != nil {
h . HandleHTTPError ( ctx , err , w )
return
}
if err = h . NotificationRuleStore . DeleteNotificationRule ( ctx , i ) ; err != nil {
h . HandleHTTPError ( ctx , err , w )
return
}
2019-12-04 23:10:23 +00:00
h . log . Debug ( "Notification rule deleted" , zap . String ( "notificationRuleID" , fmt . Sprint ( i ) ) )
2019-07-24 21:53:53 +00:00
w . WriteHeader ( http . StatusNoContent )
}
2020-03-05 00:32:33 +00:00
// NotificationRuleService is an http client that implements the NotificationRuleStore interface
type NotificationRuleService struct {
Client * httpc . Client
* UserResourceMappingService
* OrganizationService
}
// NewNotificationRuleService wraps an httpc.Client in a NotificationRuleService
func NewNotificationRuleService ( client * httpc . Client ) * NotificationRuleService {
return & NotificationRuleService {
Client : client ,
UserResourceMappingService : & UserResourceMappingService {
Client : client ,
} ,
OrganizationService : & OrganizationService {
Client : client ,
} ,
}
}
type notificationRuleCreateEncoder struct {
nrc influxdb . NotificationRuleCreate
}
func ( n notificationRuleCreateEncoder ) MarshalJSON ( ) ( [ ] byte , error ) {
b , err := n . nrc . NotificationRule . MarshalJSON ( )
if err != nil {
return nil , err
}
var v map [ string ] interface { }
err = json . Unmarshal ( b , & v )
if err != nil {
return nil , err
}
v [ "status" ] = n . nrc . Status
return json . Marshal ( v )
}
type notificationRuleDecoder struct {
rule influxdb . NotificationRule
}
func ( n * notificationRuleDecoder ) UnmarshalJSON ( b [ ] byte ) error {
newRule , err := rule . UnmarshalJSON ( b )
if err != nil {
return err
}
n . rule = newRule
return nil
}
// CreateNotificationRule creates a new NotificationRule from a NotificationRuleCreate
// the Status on the NotificationRuleCreate is used to determine the status (active/inactive) of the associated Task
func ( s * NotificationRuleService ) CreateNotificationRule ( ctx context . Context , nr influxdb . NotificationRuleCreate , userID influxdb . ID ) error {
var resp notificationRuleDecoder
err := s . Client .
PostJSON ( notificationRuleCreateEncoder { nrc : nr } , prefixNotificationRules ) .
DecodeJSON ( & resp ) .
Do ( ctx )
if err != nil {
return err
}
nr . NotificationRule . SetID ( resp . rule . GetID ( ) )
nr . NotificationRule . SetOrgID ( resp . rule . GetOrgID ( ) )
return nil
}
// FindNotificationRuleByID finds and returns one Notification Rule with a matching ID
func ( s * NotificationRuleService ) FindNotificationRuleByID ( ctx context . Context , id influxdb . ID ) ( influxdb . NotificationRule , error ) {
var resp notificationRuleResponse
err := s . Client .
Get ( getNotificationRulesIDPath ( id ) ) .
DecodeJSON ( & resp ) .
Do ( ctx )
return resp . NotificationRule , err
}
// FindNotificationRules returns a list of notification rules that match filter and the total count of matching notification rules.
// Additional options provide pagination & sorting.
func ( s * NotificationRuleService ) FindNotificationRules ( ctx context . Context , filter influxdb . NotificationRuleFilter , opt ... influxdb . FindOptions ) ( [ ] influxdb . NotificationRule , int , error ) {
2020-04-30 14:52:21 +00:00
var params = influxdb . FindOptionParams ( opt ... )
2020-03-05 00:32:33 +00:00
if filter . OrgID != nil {
params = append ( params , [ 2 ] string { "orgID" , filter . OrgID . String ( ) } )
}
if filter . Organization != nil {
params = append ( params , [ 2 ] string { "org" , * filter . Organization } )
}
if len ( filter . Tags ) != 0 {
// loop over tags and append a string of format key:value for each
for _ , tag := range filter . Tags {
keyvalue := fmt . Sprintf ( "%s:%s" , tag . Key , tag . Value )
params = append ( params , [ 2 ] string { "tag" , keyvalue } )
}
}
var resp struct {
NotificationRules [ ] notificationRuleDecoder
}
err := s . Client .
Get ( prefixNotificationRules ) .
QueryParams ( params ... ) .
DecodeJSON ( & resp ) .
Do ( ctx )
if err != nil {
return nil , 0 , err
}
var rules [ ] influxdb . NotificationRule
for _ , r := range resp . NotificationRules {
rules = append ( rules , r . rule )
}
return rules , len ( rules ) , nil
}
// UpdateNotificationRule updates a single notification rule.
// Returns the new notification rule after update.
func ( s * NotificationRuleService ) UpdateNotificationRule ( ctx context . Context , id influxdb . ID , nr influxdb . NotificationRuleCreate , userID influxdb . ID ) ( influxdb . NotificationRule , error ) {
var resp notificationRuleDecoder
err := s . Client .
PutJSON ( notificationRuleCreateEncoder { nrc : nr } , getNotificationRulesIDPath ( id ) ) .
DecodeJSON ( & resp ) .
Do ( ctx )
if err != nil {
return nil , err
}
return resp . rule , nil
}
// PatchNotificationRule updates a single notification rule with changeset.
// Returns the new notification rule state after update.
func ( s * NotificationRuleService ) PatchNotificationRule ( ctx context . Context , id influxdb . ID , upd influxdb . NotificationRuleUpdate ) ( influxdb . NotificationRule , error ) {
var resp notificationRuleDecoder
err := s . Client .
PatchJSON ( & upd , getNotificationRulesIDPath ( id ) ) .
DecodeJSON ( & resp ) .
Do ( ctx )
if err != nil {
return nil , err
}
return resp . rule , nil
}
// DeleteNotificationRule removes a notification rule by ID.
func ( s * NotificationRuleService ) DeleteNotificationRule ( ctx context . Context , id influxdb . ID ) error {
return s . Client .
Delete ( getNotificationRulesIDPath ( id ) ) .
Do ( ctx )
}
func getNotificationRulesIDPath ( id influxdb . ID ) string {
return path . Join ( prefixNotificationRules , id . String ( ) )
}