228 lines
6.1 KiB
Go
228 lines
6.1 KiB
Go
package check
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
|
|
"github.com/influxdata/flux/ast"
|
|
"github.com/influxdata/influxdb/v2"
|
|
"github.com/influxdata/influxdb/v2/kit/platform"
|
|
"github.com/influxdata/influxdb/v2/kit/platform/errors"
|
|
"github.com/influxdata/influxdb/v2/notification"
|
|
"github.com/influxdata/influxdb/v2/notification/flux"
|
|
"github.com/influxdata/influxdb/v2/query/fluxlang"
|
|
)
|
|
|
|
// Base will embed inside a check.
|
|
type Base struct {
|
|
ID platform.ID `json:"id,omitempty"`
|
|
Name string `json:"name"`
|
|
Description string `json:"description,omitempty"`
|
|
OwnerID platform.ID `json:"ownerID,omitempty"`
|
|
OrgID platform.ID `json:"orgID,omitempty"`
|
|
Query influxdb.DashboardQuery `json:"query"`
|
|
|
|
// Care should be taken to prevent TaskID from being exposed publicly.
|
|
TaskID platform.ID `json:"taskID,omitempty"`
|
|
// } todo: separate these
|
|
// NonCustomCheckBase will embed inside non-custom checks.
|
|
// type NonCustomCheckBase struct {
|
|
StatusMessageTemplate string `json:"statusMessageTemplate"`
|
|
Cron string `json:"cron,omitempty"`
|
|
Every *notification.Duration `json:"every,omitempty"`
|
|
// Offset represents a delay before execution.
|
|
// It gets marshalled from a string duration, i.e.: "10s" is 10 seconds
|
|
Offset *notification.Duration `json:"offset,omitempty"`
|
|
|
|
Tags []influxdb.Tag `json:"tags"`
|
|
influxdb.CRUDLog
|
|
}
|
|
|
|
// Valid returns err if the check is invalid.
|
|
func (b Base) Valid(lang fluxlang.FluxLanguageService) error {
|
|
if !b.ID.Valid() {
|
|
return &errors.Error{
|
|
Code: errors.EInvalid,
|
|
Msg: "Check ID is invalid",
|
|
}
|
|
}
|
|
if b.Name == "" {
|
|
return &errors.Error{
|
|
Code: errors.EInvalid,
|
|
Msg: "Check Name can't be empty",
|
|
}
|
|
}
|
|
if !b.OrgID.Valid() {
|
|
return &errors.Error{
|
|
Code: errors.EInvalid,
|
|
Msg: "Check OrgID is invalid",
|
|
}
|
|
}
|
|
if b.Every == nil {
|
|
return &errors.Error{
|
|
Code: errors.EInvalid,
|
|
Msg: "Check Every must exist",
|
|
}
|
|
}
|
|
if len(b.Every.Values) == 0 {
|
|
return &errors.Error{
|
|
Code: errors.EInvalid,
|
|
Msg: "Check Every can't be empty",
|
|
}
|
|
}
|
|
if b.Offset != nil && len(b.Offset.Values) == 0 {
|
|
return &errors.Error{
|
|
Code: errors.EInvalid,
|
|
Msg: "Check Offset can't be empty",
|
|
}
|
|
}
|
|
if b.Offset != nil && b.Offset.TimeDuration() >= b.Every.TimeDuration() {
|
|
return &errors.Error{
|
|
Code: errors.EInvalid,
|
|
Msg: "Offset should not be equal or greater than the interval",
|
|
}
|
|
}
|
|
for _, tag := range b.Tags {
|
|
if err := tag.Valid(); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (b Base) generateFluxASTMessageFunction() ast.Statement {
|
|
fn := flux.Function(flux.FunctionParams("r"), flux.String(b.StatusMessageTemplate))
|
|
return flux.DefineVariable("messageFn", fn)
|
|
}
|
|
|
|
func (b Base) generateTaskOption() ast.Statement {
|
|
props := []*ast.Property{}
|
|
|
|
props = append(props, flux.Property("name", flux.String(b.Name)))
|
|
|
|
if b.Every != nil {
|
|
props = append(props, flux.Property("every", (*ast.DurationLiteral)(b.Every)))
|
|
}
|
|
|
|
if b.Offset != nil {
|
|
props = append(props, flux.Property("offset", (*ast.DurationLiteral)(b.Offset)))
|
|
}
|
|
|
|
return flux.DefineTaskOption(flux.Object(props...))
|
|
}
|
|
|
|
func (b Base) generateFluxASTCheckDefinition(checkType string) ast.Statement {
|
|
props := append([]*ast.Property{}, flux.Property("_check_id", flux.String(b.ID.String())))
|
|
props = append(props, flux.Property("_check_name", flux.String(b.Name)))
|
|
props = append(props, flux.Property("_type", flux.String(checkType)))
|
|
|
|
// TODO(desa): eventually tags will be flattened out into the data struct
|
|
tagProps := []*ast.Property{}
|
|
for _, tag := range b.Tags {
|
|
tagProps = append(tagProps, flux.Property(tag.Key, flux.String(tag.Value)))
|
|
}
|
|
|
|
props = append(props, flux.Property("tags", flux.Object(tagProps...)))
|
|
|
|
return flux.DefineVariable("check", flux.Object(props...))
|
|
}
|
|
|
|
// GetID implements influxdb.Getter interface.
|
|
func (b Base) GetID() platform.ID {
|
|
return b.ID
|
|
}
|
|
|
|
// GetOrgID implements influxdb.Getter interface.
|
|
func (b Base) GetOrgID() platform.ID {
|
|
return b.OrgID
|
|
}
|
|
|
|
// GetOwnerID gets the ownerID associated with a Base.
|
|
func (b Base) GetOwnerID() platform.ID {
|
|
return b.OwnerID
|
|
}
|
|
|
|
// GetTaskID retrieves the task ID for a check.
|
|
func (b Base) GetTaskID() platform.ID {
|
|
return b.TaskID
|
|
}
|
|
|
|
// GetCRUDLog implements influxdb.Getter interface.
|
|
func (b Base) GetCRUDLog() influxdb.CRUDLog {
|
|
return b.CRUDLog
|
|
}
|
|
|
|
// GetName implements influxdb.Getter interface.
|
|
func (b *Base) GetName() string {
|
|
return b.Name
|
|
}
|
|
|
|
// GetDescription implements influxdb.Getter interface.
|
|
func (b *Base) GetDescription() string {
|
|
return b.Description
|
|
}
|
|
|
|
// SetID will set the primary key.
|
|
func (b *Base) SetID(id platform.ID) {
|
|
b.ID = id
|
|
}
|
|
|
|
// SetOrgID will set the org key.
|
|
func (b *Base) SetOrgID(id platform.ID) {
|
|
b.OrgID = id
|
|
}
|
|
|
|
// ClearPrivateData remove any data that we don't want to be exposed publicly.
|
|
func (b *Base) ClearPrivateData() {
|
|
b.TaskID = 0
|
|
}
|
|
|
|
// SetTaskID sets the taskID for a check.
|
|
func (b *Base) SetTaskID(id platform.ID) {
|
|
b.TaskID = id
|
|
}
|
|
|
|
// SetOwnerID sets the taskID for a check.
|
|
func (b *Base) SetOwnerID(id platform.ID) {
|
|
b.OwnerID = id
|
|
}
|
|
|
|
// SetName implements influxdb.Updator interface.
|
|
func (b *Base) SetName(name string) {
|
|
b.Name = name
|
|
}
|
|
|
|
// SetDescription implements influxdb.Updator interface.
|
|
func (b *Base) SetDescription(description string) {
|
|
b.Description = description
|
|
}
|
|
|
|
var typeToCheck = map[string](func() influxdb.Check){
|
|
"deadman": func() influxdb.Check { return &Deadman{} },
|
|
"threshold": func() influxdb.Check { return &Threshold{} },
|
|
"custom": func() influxdb.Check { return &Custom{} },
|
|
}
|
|
|
|
// UnmarshalJSON will convert
|
|
func UnmarshalJSON(b []byte) (influxdb.Check, error) {
|
|
var raw struct {
|
|
Type string `json:"type"`
|
|
}
|
|
if err := json.Unmarshal(b, &raw); err != nil {
|
|
return nil, &errors.Error{
|
|
Code: errors.EInvalid,
|
|
Msg: "unable to detect the check type from json",
|
|
}
|
|
}
|
|
convertedFunc, ok := typeToCheck[raw.Type]
|
|
if !ok {
|
|
return nil, &errors.Error{
|
|
Msg: fmt.Sprintf("invalid check type %s", raw.Type),
|
|
}
|
|
}
|
|
converted := convertedFunc()
|
|
err := json.Unmarshal(b, converted)
|
|
return converted, err
|
|
}
|