Skip to content

Commit

Permalink
chore(pkger): refactor parser notification endpoint state out into st…
Browse files Browse the repository at this point in the history
…ateful type

references: #17434
  • Loading branch information
jsteenb2 committed Apr 15, 2020
1 parent b15d49e commit ce6cb97
Show file tree
Hide file tree
Showing 9 changed files with 531 additions and 475 deletions.
5 changes: 5 additions & 0 deletions cmd/influxd/launcher/pkger_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"errors"
"fmt"
"reflect"
"testing"
"time"

Expand Down Expand Up @@ -259,6 +260,10 @@ func TestLauncher_Pkger(t *testing.T) {
})

t.Run("an error during application roles back resources to previous state", func(t *testing.T) {
if reflect.DeepEqual(initialSum, pkger.Summary{}) {
t.Skip("test setup not complete")
}

logger := l.log.With(zap.String("service", "pkger"))
var svc pkger.SVC = pkger.NewService(
pkger.WithLogger(logger),
Expand Down
4 changes: 2 additions & 2 deletions http/swagger.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7657,8 +7657,8 @@ components:
items:
type: object
properties:
remove:
type: boolean
stateStatus:
type: string
id:
type: string
pkgName:
Expand Down
324 changes: 0 additions & 324 deletions pkger/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"encoding/json"
"errors"
"fmt"
"net/url"
"reflect"
"regexp"
"sort"
Expand Down Expand Up @@ -391,26 +390,6 @@ type DiffNotificationEndpoint struct {
Old *DiffNotificationEndpointValues `json:"old"`
}

func newDiffNotificationEndpoint(ne *notificationEndpoint, i influxdb.NotificationEndpoint) DiffNotificationEndpoint {
diff := DiffNotificationEndpoint{
DiffIdentifier: DiffIdentifier{
ID: SafeID(ne.ID()),
Remove: ne.shouldRemove,
PkgName: ne.PkgName(),
},
New: DiffNotificationEndpointValues{
NotificationEndpoint: ne.summarize().NotificationEndpoint,
},
}
if i != nil {
diff.ID = SafeID(i.GetID())
diff.Old = &DiffNotificationEndpointValues{
NotificationEndpoint: i,
}
}
return diff
}

type (
// DiffNotificationRule is a diff of an individual notification rule.
DiffNotificationRule struct {
Expand Down Expand Up @@ -877,309 +856,6 @@ type SummaryVariable struct {
LabelAssociations []SummaryLabel `json:"labelAssociations"`
}

type thresholdType string

const (
thresholdTypeGreater thresholdType = "greater"
thresholdTypeLesser thresholdType = "lesser"
thresholdTypeInsideRange thresholdType = "inside_range"
thresholdTypeOutsideRange thresholdType = "outside_range"
)

var thresholdTypes = map[thresholdType]bool{
thresholdTypeGreater: true,
thresholdTypeLesser: true,
thresholdTypeInsideRange: true,
thresholdTypeOutsideRange: true,
}

type threshold struct {
threshType thresholdType
allVals bool
level string
val float64
min, max float64
}

func (t threshold) valid() []validationErr {
var vErrs []validationErr
if notification.ParseCheckLevel(t.level) == notification.Unknown {
vErrs = append(vErrs, validationErr{
Field: fieldLevel,
Msg: fmt.Sprintf("must be 1 in [CRIT, WARN, INFO, OK]; got=%q", t.level),
})
}
if !thresholdTypes[t.threshType] {
vErrs = append(vErrs, validationErr{
Field: fieldType,
Msg: fmt.Sprintf("must be 1 in [Lesser, Greater, Inside_Range, Outside_Range]; got=%q", t.threshType),
})
}
if t.min > t.max {
vErrs = append(vErrs, validationErr{
Field: fieldMin,
Msg: "min must be < max",
})
}
return vErrs
}

func toInfluxThresholds(thresholds ...threshold) []icheck.ThresholdConfig {
var iThresh []icheck.ThresholdConfig
for _, th := range thresholds {
base := icheck.ThresholdConfigBase{
AllValues: th.allVals,
Level: notification.ParseCheckLevel(th.level),
}
switch th.threshType {
case thresholdTypeGreater:
iThresh = append(iThresh, icheck.Greater{
ThresholdConfigBase: base,
Value: th.val,
})
case thresholdTypeLesser:
iThresh = append(iThresh, icheck.Lesser{
ThresholdConfigBase: base,
Value: th.val,
})
case thresholdTypeInsideRange, thresholdTypeOutsideRange:
iThresh = append(iThresh, icheck.Range{
ThresholdConfigBase: base,
Max: th.max,
Min: th.min,
Within: th.threshType == thresholdTypeInsideRange,
})
}
}
return iThresh
}

type notificationKind int

const (
notificationKindHTTP notificationKind = iota + 1
notificationKindPagerDuty
notificationKindSlack
)

const (
notificationHTTPAuthTypeBasic = "basic"
notificationHTTPAuthTypeBearer = "bearer"
notificationHTTPAuthTypeNone = "none"
)

const (
fieldNotificationEndpointHTTPMethod = "method"
fieldNotificationEndpointPassword = "password"
fieldNotificationEndpointRoutingKey = "routingKey"
fieldNotificationEndpointToken = "token"
fieldNotificationEndpointURL = "url"
fieldNotificationEndpointUsername = "username"
)

type notificationEndpoint struct {
identity

kind notificationKind
id influxdb.ID
OrgID influxdb.ID
description string
method string
password *references
routingKey *references
status string
token *references
httpType string
url string
username *references

labels sortedLabels

existing influxdb.NotificationEndpoint
}

func (n *notificationEndpoint) Exists() bool {
return n.existing != nil
}

func (n *notificationEndpoint) ID() influxdb.ID {
if n.existing != nil {
return n.existing.GetID()
}
return n.id
}

func (n *notificationEndpoint) Labels() []*label {
return n.labels
}

func (n *notificationEndpoint) ResourceType() influxdb.ResourceType {
return KindNotificationEndpointSlack.ResourceType()
}

func (n *notificationEndpoint) base() endpoint.Base {
e := endpoint.Base{
Name: n.Name(),
Description: n.description,
Status: n.influxStatus(),
}
if id := n.ID(); id > 0 {
e.ID = &id
}
if orgID := n.OrgID; orgID > 0 {
e.OrgID = &orgID
}
return e
}

func (n *notificationEndpoint) summarize() SummaryNotificationEndpoint {
base := n.base()
sum := SummaryNotificationEndpoint{
PkgName: n.PkgName(),
LabelAssociations: toSummaryLabels(n.labels...),
}

switch n.kind {
case notificationKindHTTP:
e := &endpoint.HTTP{
Base: base,
URL: n.url,
Method: n.method,
}
switch n.httpType {
case notificationHTTPAuthTypeBasic:
e.AuthMethod = notificationHTTPAuthTypeBasic
e.Password = n.password.SecretField()
e.Username = n.username.SecretField()
case notificationHTTPAuthTypeBearer:
e.AuthMethod = notificationHTTPAuthTypeBearer
e.Token = n.token.SecretField()
case notificationHTTPAuthTypeNone:
e.AuthMethod = notificationHTTPAuthTypeNone
}
sum.NotificationEndpoint = e
case notificationKindPagerDuty:
sum.NotificationEndpoint = &endpoint.PagerDuty{
Base: base,
ClientURL: n.url,
RoutingKey: n.routingKey.SecretField(),
}
case notificationKindSlack:
sum.NotificationEndpoint = &endpoint.Slack{
Base: base,
URL: n.url,
Token: n.token.SecretField(),
}
}
return sum
}

func (n *notificationEndpoint) influxStatus() influxdb.Status {
status := influxdb.Active
if n.status != "" {
status = influxdb.Status(n.status)
}
return status
}

var validEndpointHTTPMethods = map[string]bool{
"DELETE": true,
"GET": true,
"HEAD": true,
"OPTIONS": true,
"PATCH": true,
"POST": true,
"PUT": true,
}

func (n *notificationEndpoint) valid() []validationErr {
var failures []validationErr
if _, err := url.Parse(n.url); err != nil || n.url == "" {
failures = append(failures, validationErr{
Field: fieldNotificationEndpointURL,
Msg: "must be valid url",
})
}

status := influxdb.Status(n.status)
if status != "" && influxdb.Inactive != status && influxdb.Active != status {
failures = append(failures, validationErr{
Field: fieldStatus,
Msg: "not a valid status; valid statues are one of [active, inactive]",
})
}

switch n.kind {
case notificationKindPagerDuty:
if !n.routingKey.hasValue() {
failures = append(failures, validationErr{
Field: fieldNotificationEndpointRoutingKey,
Msg: "must be provide",
})
}
case notificationKindHTTP:
if !validEndpointHTTPMethods[n.method] {
failures = append(failures, validationErr{
Field: fieldNotificationEndpointHTTPMethod,
Msg: "http method must be a valid HTTP verb",
})
}

switch n.httpType {
case notificationHTTPAuthTypeBasic:
if !n.password.hasValue() {
failures = append(failures, validationErr{
Field: fieldNotificationEndpointPassword,
Msg: "must provide non empty string",
})
}
if !n.username.hasValue() {
failures = append(failures, validationErr{
Field: fieldNotificationEndpointUsername,
Msg: "must provide non empty string",
})
}
case notificationHTTPAuthTypeBearer:
if !n.token.hasValue() {
failures = append(failures, validationErr{
Field: fieldNotificationEndpointToken,
Msg: "must provide non empty string",
})
}
case notificationHTTPAuthTypeNone:
default:
failures = append(failures, validationErr{
Field: fieldType,
Msg: fmt.Sprintf(
"invalid type provided %q; valid type is 1 in [%s, %s, %s]",
n.httpType,
notificationHTTPAuthTypeBasic,
notificationHTTPAuthTypeBearer,
notificationHTTPAuthTypeNone,
),
})
}
}

if len(failures) > 0 {
return []validationErr{
objectValidationErr(fieldSpec, failures...),
}
}

return nil
}

type mapperNotificationEndpoints []*notificationEndpoint

func (n mapperNotificationEndpoints) Association(i int) labelAssociater {
return n[i]
}

func (n mapperNotificationEndpoints) Len() int {
return len(n)
}

const (
fieldNotificationRuleChannel = "channel"
fieldNotificationRuleCurrentLevel = "currentLevel"
Expand Down
5 changes: 0 additions & 5 deletions pkger/models_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -486,11 +486,6 @@ func TestPkg(t *testing.T) {
kind: KindLabel,
validName: "label_1",
},
{
pkgFile: "testdata/notification_endpoint.yml",
kind: KindNotificationEndpoint,
validName: "slack_notification_endpoint",
},
{
pkgFile: "testdata/notification_rule.yml",
kind: KindNotificationRule,
Expand Down
Loading

0 comments on commit ce6cb97

Please sign in to comment.