feat(pkger): add support for notification endpoints to parser

pull/16150/head
Johnny Steenbergen 2019-12-05 23:05:32 -08:00 committed by Johnny Steenbergen
parent 34c0a69abf
commit 4a888cc706
5 changed files with 808 additions and 41 deletions

View File

@ -3,32 +3,40 @@ package pkger
import (
"errors"
"fmt"
"net/url"
"reflect"
"strconv"
"strings"
"time"
"github.com/influxdata/influxdb"
"github.com/influxdata/influxdb/notification/endpoint"
)
// Package kinds.
const (
KindUnknown Kind = ""
KindBucket Kind = "bucket"
KindDashboard Kind = "dashboard"
KindLabel Kind = "label"
KindPackage Kind = "package"
KindTelegraf Kind = "telegraf"
KindVariable Kind = "variable"
KindUnknown Kind = ""
KindBucket Kind = "bucket"
KindDashboard Kind = "dashboard"
KindLabel Kind = "label"
KindNotificationEndpointPagerDuty Kind = "notificationendpointpagerduty"
KindNotificationEndpointHTTP Kind = "notificationendpointhttp"
KindNotificationEndpointSlack Kind = "notificationendpointslack"
KindPackage Kind = "package"
KindTelegraf Kind = "telegraf"
KindVariable Kind = "variable"
)
var kinds = map[Kind]bool{
KindBucket: true,
KindDashboard: true,
KindLabel: true,
KindPackage: true,
KindTelegraf: true,
KindVariable: true,
KindBucket: true,
KindDashboard: true,
KindLabel: true,
KindNotificationEndpointHTTP: true,
KindNotificationEndpointPagerDuty: true,
KindNotificationEndpointSlack: true,
KindPackage: true,
KindTelegraf: true,
KindVariable: true,
}
// Kind is a resource kind.
@ -71,6 +79,10 @@ func (k Kind) ResourceType() influxdb.ResourceType {
return influxdb.DashboardsResourceType
case KindLabel:
return influxdb.LabelsResourceType
case KindNotificationEndpointHTTP,
KindNotificationEndpointPagerDuty,
KindNotificationEndpointSlack:
return influxdb.NotificationEndpointResourceType
case KindTelegraf:
return influxdb.TelegrafsResourceType
case KindVariable:
@ -335,12 +347,13 @@ func (d DiffVariable) hasConflict() bool {
// Summary is a definition of all the resources that have or
// will be created from a pkg.
type Summary struct {
Buckets []SummaryBucket `json:"buckets"`
Dashboards []SummaryDashboard `json:"dashboards"`
Labels []SummaryLabel `json:"labels"`
LabelMappings []SummaryLabelMapping `json:"labelMappings"`
TelegrafConfigs []SummaryTelegraf `json:"telegrafConfigs"`
Variables []SummaryVariable `json:"variables"`
Buckets []SummaryBucket `json:"buckets"`
Dashboards []SummaryDashboard `json:"dashboards"`
NotificationEndpoints []SummaryNotificationEndpoint `json:"notificationEndpoints"`
Labels []SummaryLabel `json:"labels"`
LabelMappings []SummaryLabelMapping `json:"labelMappings"`
TelegrafConfigs []SummaryTelegraf `json:"telegrafConfigs"`
Variables []SummaryVariable `json:"variables"`
}
// SummaryBucket provides a summary of a pkg bucket.
@ -404,6 +417,12 @@ type SummaryChart struct {
Width int `json:"width"`
}
// SummaryNotificationEndpoint provides a summary of a pkg endpoint rule.
type SummaryNotificationEndpoint struct {
influxdb.NotificationEndpoint
LabelAssociations []influxdb.Label `json:"labelAssociations"`
}
// SummaryLabel provides a summary of a pkg label.
type SummaryLabel struct {
influxdb.Label
@ -438,6 +457,7 @@ const (
fieldPrefix = "prefix"
fieldQuery = "query"
fieldSuffix = "suffix"
fieldStatus = "status"
fieldType = "type"
fieldValue = "value"
fieldValues = "values"
@ -721,6 +741,156 @@ func (s sortedLabels) Swap(i, j int) {
s[i], s[j] = s[j], s[i]
}
type notificationKind int
const (
notificationKindHTTP notificationKind = iota + 1
notificationKindPagerDuty
notificationKindSlack
)
const (
notificationHTTPAuthTypeBasic = "basic"
notificationHTTPAuthTypeBearer = "bearer"
notificationHTTPAuthTypeNone = "none"
)
const (
fieldNotificationEndpointPassword = "password"
fieldNotificationEndpointRoutingKey = "routingKey"
fieldNotificationEndpointToken = "token"
fieldNotificationEndpointURL = "url"
fieldNotificationEndpointUsername = "username"
)
type notificationEndpoint struct {
kind notificationKind
name string
description string
password string
routingKey string
status string
token string
httpType string
url string
username string
labels sortedLabels
}
func (n *notificationEndpoint) Name() string {
return n.name
}
func (n *notificationEndpoint) ResourceType() influxdb.ResourceType {
return KindNotificationEndpointSlack.ResourceType()
}
func (n *notificationEndpoint) summarize() SummaryNotificationEndpoint {
base := endpoint.Base{
Name: n.Name(),
Description: n.description,
Status: influxdb.TaskStatusActive,
}
if n.status != "" {
base.Status = influxdb.Status(n.status)
}
sum := SummaryNotificationEndpoint{
LabelAssociations: toInfluxLabels(n.labels...),
}
switch n.kind {
case notificationKindHTTP:
e := &endpoint.HTTP{
Base: base,
URL: n.url,
Method: "POST",
}
switch {
case n.password == "" && n.username == "" && n.token == "":
e.AuthMethod = notificationHTTPAuthTypeNone
case n.token != "":
e.AuthMethod = notificationHTTPAuthTypeBearer
default:
e.AuthMethod = notificationHTTPAuthTypeBasic
}
sum.NotificationEndpoint = e
case notificationKindPagerDuty:
sum.NotificationEndpoint = &endpoint.PagerDuty{
Base: base,
ClientURL: n.url,
}
case notificationKindSlack:
sum.NotificationEndpoint = &endpoint.Slack{
Base: base,
URL: n.url,
}
}
return sum
}
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",
})
}
if n.status != "" && influxdb.TaskStatusInactive != n.status && influxdb.TaskStatusActive != n.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 == "" {
failures = append(failures, validationErr{
Field: fieldNotificationEndpointRoutingKey,
Msg: "must provide non empty string",
})
}
case notificationKindHTTP:
switch n.httpType {
case notificationHTTPAuthTypeBasic:
if n.password == "" {
failures = append(failures, validationErr{
Field: fieldNotificationEndpointPassword,
Msg: "must provide non empty string",
})
}
if n.username == "" {
failures = append(failures, validationErr{
Field: fieldNotificationEndpointUsername,
Msg: "must provide non empty string",
})
}
case notificationHTTPAuthTypeBearer:
if n.token == "" {
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,
),
})
}
}
return failures
}
const (
fieldTelegrafConfig = "config"
)

View File

@ -133,11 +133,12 @@ type Pkg struct {
Resources []Resource `yaml:"resources" json:"resources"`
} `yaml:"spec" json:"spec"`
mLabels map[string]*label
mBuckets map[string]*bucket
mDashboards []*dashboard
mVariables map[string]*variable
mTelegrafs []*telegraf
mLabels map[string]*label
mBuckets map[string]*bucket
mDashboards []*dashboard
mNotificationEndpoints map[string]*notificationEndpoint
mTelegrafs []*telegraf
mVariables map[string]*variable
isVerified bool // dry run has verified pkg resources with existing resources
isParsed bool // indicates the pkg has been parsed and all resources graphed accordingly
@ -169,6 +170,10 @@ func (p *Pkg) Summary() Summary {
})
}
for _, n := range p.notificationEndpoints() {
sum.NotificationEndpoints = append(sum.NotificationEndpoints, n.summarize())
}
for _, t := range p.telegrafs() {
sum.TelegrafConfigs = append(sum.TelegrafConfigs, t.summarize())
}
@ -259,6 +264,21 @@ func (p *Pkg) dashboards() []*dashboard {
return dashes
}
func (p *Pkg) notificationEndpoints() []*notificationEndpoint {
endpoints := make([]*notificationEndpoint, 0, len(p.mNotificationEndpoints))
for _, e := range p.mNotificationEndpoints {
endpoints = append(endpoints, e)
}
sort.Slice(endpoints, func(i, j int) bool {
ei, ej := endpoints[i], endpoints[j]
if ei.kind == ej.kind {
return ei.Name() < ej.Name()
}
return ei.kind < ej.kind
})
return endpoints
}
func (p *Pkg) telegrafs() []*telegraf {
teles := p.mTelegrafs[:]
sort.Slice(teles, func(i, j int) bool { return teles[i].Name() < teles[j].Name() })
@ -375,23 +395,20 @@ func (p *Pkg) validResources() error {
}
func (p *Pkg) graphResources() error {
graphFns := []func() error{
// labels are first to validate associations with other resources
graphFns := []func() *parseErr{
// labels are first, this is to validate associations with other resources
p.graphLabels,
p.graphVariables,
p.graphBuckets,
p.graphDashboards,
p.graphNotificationEndpoints,
p.graphTelegrafs,
}
var pErr parseErr
for _, fn := range graphFns {
if err := fn(); err != nil {
if IsParseErr(err) {
pErr.append(err.(*parseErr).Resources...)
continue
}
return err
pErr.append(err.Resources...)
}
}
@ -406,7 +423,7 @@ func (p *Pkg) graphResources() error {
return nil
}
func (p *Pkg) graphBuckets() error {
func (p *Pkg) graphBuckets() *parseErr {
p.mBuckets = make(map[string]*bucket)
return p.eachResource(KindBucket, 2, func(r Resource) []validationErr {
if _, ok := p.mBuckets[r.Name()]; ok {
@ -444,7 +461,7 @@ func (p *Pkg) graphBuckets() error {
})
}
func (p *Pkg) graphLabels() error {
func (p *Pkg) graphLabels() *parseErr {
p.mLabels = make(map[string]*label)
return p.eachResource(KindLabel, 2, func(r Resource) []validationErr {
if _, ok := p.mLabels[r.Name()]; ok {
@ -463,7 +480,7 @@ func (p *Pkg) graphLabels() error {
})
}
func (p *Pkg) graphDashboards() error {
func (p *Pkg) graphDashboards() *parseErr {
p.mDashboards = make([]*dashboard, 0)
return p.eachResource(KindDashboard, 2, func(r Resource) []validationErr {
dash := &dashboard{
@ -497,7 +514,70 @@ func (p *Pkg) graphDashboards() error {
})
}
func (p *Pkg) graphVariables() error {
func (p *Pkg) graphNotificationEndpoints() *parseErr {
p.mNotificationEndpoints = make(map[string]*notificationEndpoint)
notificationKinds := []struct {
kind Kind
notificationKind notificationKind
}{
{
kind: KindNotificationEndpointHTTP,
notificationKind: notificationKindHTTP,
},
{
kind: KindNotificationEndpointPagerDuty,
notificationKind: notificationKindPagerDuty,
},
{
kind: KindNotificationEndpointSlack,
notificationKind: notificationKindSlack,
},
}
var pErr parseErr
for _, nk := range notificationKinds {
err := p.eachResource(nk.kind, 1, func(r Resource) []validationErr {
if _, ok := p.mNotificationEndpoints[r.Name()]; ok {
return []validationErr{{
Field: "name",
Msg: "duplicate name: " + r.Name(),
}}
}
endpoint := &notificationEndpoint{
kind: nk.notificationKind,
name: r.Name(),
description: r.stringShort(fieldDescription),
httpType: strings.ToLower(r.stringShort(fieldType)),
password: r.stringShort(fieldNotificationEndpointPassword),
routingKey: r.stringShort(fieldNotificationEndpointRoutingKey),
status: strings.ToLower(r.stringShort(fieldStatus)),
token: r.stringShort(fieldNotificationEndpointToken),
url: r.stringShort(fieldNotificationEndpointURL),
username: r.stringShort(fieldNotificationEndpointUsername),
}
failures := p.parseNestedLabels(r, func(l *label) error {
endpoint.labels = append(endpoint.labels, l)
p.mLabels[l.Name()].setMapping(endpoint, false)
return nil
})
sort.Sort(endpoint.labels)
p.mNotificationEndpoints[endpoint.Name()] = endpoint
return append(failures, endpoint.valid()...)
})
if err != nil {
pErr.append(err.Resources...)
}
}
if len(pErr.Resources) > 0 {
return &pErr
}
return nil
}
func (p *Pkg) graphVariables() *parseErr {
p.mVariables = make(map[string]*variable)
return p.eachResource(KindVariable, 1, func(r Resource) []validationErr {
if _, ok := p.mVariables[r.Name()]; ok {
@ -531,7 +611,7 @@ func (p *Pkg) graphVariables() error {
})
}
func (p *Pkg) graphTelegrafs() error {
func (p *Pkg) graphTelegrafs() *parseErr {
p.mTelegrafs = make([]*telegraf, 0)
return p.eachResource(KindTelegraf, 0, func(r Resource) []validationErr {
tele := new(telegraf)
@ -559,7 +639,7 @@ func (p *Pkg) graphTelegrafs() error {
})
}
func (p *Pkg) eachResource(resourceKind Kind, minNameLen int, fn func(r Resource) []validationErr) error {
func (p *Pkg) eachResource(resourceKind Kind, minNameLen int, fn func(r Resource) []validationErr) *parseErr {
var pErr parseErr
for i, r := range p.Spec.Resources {
k, err := r.kind()

View File

@ -8,6 +8,7 @@ import (
"time"
"github.com/influxdata/influxdb"
"github.com/influxdata/influxdb/notification/endpoint"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@ -132,7 +133,7 @@ spec:
{
name: "missing name",
validationErrs: 1,
valFields: []string{"name"},
valFields: []string{fieldName},
pkgStr: `apiVersion: 0.1.0
kind: Package
meta:
@ -147,7 +148,7 @@ spec:
{
name: "mixed valid and missing name",
validationErrs: 1,
valFields: []string{"name"},
valFields: []string{fieldName},
pkgStr: `apiVersion: 0.1.0
kind: Package
meta:
@ -166,7 +167,7 @@ spec:
name: "mixed valid and multiple bad names",
resourceErrs: 2,
validationErrs: 1,
valFields: []string{"name"},
valFields: []string{fieldName},
pkgStr: `apiVersion: 0.1.0
kind: Package
meta:
@ -187,7 +188,7 @@ spec:
name: "duplicate bucket names",
resourceErrs: 1,
validationErrs: 1,
valFields: []string{"name"},
valFields: []string{fieldName},
pkgStr: `apiVersion: 0.1.0
kind: Package
meta:
@ -2703,6 +2704,373 @@ spec:
})
})
t.Run("pkg with notification endpoints and labels associated", func(t *testing.T) {
testfileRunner(t, "testdata/notification_endpoint", func(t *testing.T, pkg *Pkg) {
expectedEndpoints := []SummaryNotificationEndpoint{
{
NotificationEndpoint: &endpoint.HTTP{
Base: endpoint.Base{
Name: "http_basic_auth_notification_endpoint",
Description: "http basic auth desc",
Status: influxdb.TaskStatusInactive,
},
URL: "https://www.example.com/endpoint/basicauth",
AuthMethod: "basic",
Method: "POST",
},
},
{
NotificationEndpoint: &endpoint.HTTP{
Base: endpoint.Base{
Name: "http_bearer_auth_notification_endpoint",
Description: "http bearer auth desc",
Status: influxdb.TaskStatusActive,
},
URL: "https://www.example.com/endpoint/bearerauth",
AuthMethod: "bearer",
Method: "POST",
},
},
{
NotificationEndpoint: &endpoint.HTTP{
Base: endpoint.Base{
Name: "http_none_auth_notification_endpoint",
Description: "http none auth desc",
Status: influxdb.TaskStatusActive,
},
URL: "https://www.example.com/endpoint/noneauth",
AuthMethod: "none",
Method: "POST",
},
},
{
NotificationEndpoint: &endpoint.PagerDuty{
Base: endpoint.Base{
Name: "pager_duty_notification_endpoint",
Description: "pager duty desc",
Status: influxdb.TaskStatusActive,
},
ClientURL: "http://localhost:8080/orgs/7167eb6719fa34e5/alert-history",
},
},
{
NotificationEndpoint: &endpoint.Slack{
Base: endpoint.Base{
Name: "slack_notification_endpoint",
Description: "slack desc",
Status: influxdb.TaskStatusActive,
},
URL: "https://hooks.slack.com/services/bip/piddy/boppidy",
},
},
}
sum := pkg.Summary()
endpoints := sum.NotificationEndpoints
require.Len(t, endpoints, len(expectedEndpoints))
for i := range expectedEndpoints {
expected, actual := expectedEndpoints[i], endpoints[i]
assert.Equalf(t, expected.NotificationEndpoint, actual.NotificationEndpoint, "index=%d", i)
require.Len(t, actual.LabelAssociations, 1)
assert.Equal(t, "label_1", actual.LabelAssociations[0].Name)
require.Len(t, sum.LabelMappings, len(expectedEndpoints))
expectedMapping := SummaryLabelMapping{
ResourceName: expected.GetName(),
LabelName: "label_1",
LabelMapping: influxdb.LabelMapping{
ResourceType: influxdb.NotificationEndpointResourceType,
},
}
assert.Contains(t, sum.LabelMappings, expectedMapping)
}
})
t.Run("handles bad config", func(t *testing.T) {
tests := []struct {
kind Kind
resErr testPkgResourceError
}{
{
kind: KindNotificationEndpointSlack,
resErr: testPkgResourceError{
name: "missing slack url",
validationErrs: 1,
valFields: []string{fieldNotificationEndpointURL},
pkgStr: `apiVersion: 0.1.0
kind: Package
meta:
pkgName: pkg_name
pkgVersion: 1
description: pack description
spec:
resources:
- kind: NotificationEndpointSlack
name: name1
`,
},
},
{
kind: KindNotificationEndpointPagerDuty,
resErr: testPkgResourceError{
name: "missing pager duty url",
validationErrs: 1,
valFields: []string{fieldNotificationEndpointURL},
pkgStr: `apiVersion: 0.1.0
kind: Package
meta:
pkgName: pkg_name
pkgVersion: 1
description: pack description
spec:
resources:
- kind: NotificationEndpointPagerDuty
name: name1
`,
},
},
{
kind: KindNotificationEndpointHTTP,
resErr: testPkgResourceError{
name: "missing http url",
validationErrs: 1,
valFields: []string{fieldNotificationEndpointURL},
pkgStr: `apiVersion: 0.1.0
kind: Package
meta:
pkgName: pkg_name
pkgVersion: 1
description: pack description
spec:
resources:
- kind: NotificationEndpointHTTP
name: name1
`,
},
},
{
kind: KindNotificationEndpointHTTP,
resErr: testPkgResourceError{
name: "bad url",
validationErrs: 1,
valFields: []string{fieldNotificationEndpointURL},
pkgStr: `apiVersion: 0.1.0
kind: Package
meta:
pkgName: pkg_name
pkgVersion: 1
description: pack description
spec:
resources:
- kind: NotificationEndpointHTTP
name: name1
type: none
url: d_____-_8**(*https://www.examples.coms
`,
},
},
{
kind: KindNotificationEndpointHTTP,
resErr: testPkgResourceError{
name: "bad url",
validationErrs: 1,
valFields: []string{fieldNotificationEndpointURL},
pkgStr: `apiVersion: 0.1.0
kind: Package
meta:
pkgName: pkg_name
pkgVersion: 1
description: pack description
spec:
resources:
- kind: NotificationEndpointHTTP
name: name1
type: none
url: d_____-_8**(*https://www.examples.coms
`,
},
},
{
kind: KindNotificationEndpointHTTP,
resErr: testPkgResourceError{
name: "missing basic username",
validationErrs: 1,
valFields: []string{fieldNotificationEndpointUsername},
pkgStr: `apiVersion: 0.1.0
kind: Package
meta:
pkgName: pkg_name
pkgVersion: 1
description: pack description
spec:
resources:
- kind: NotificationEndpointHTTP
name: name1
type: basic
url: example.com
password: password
`,
},
},
{
kind: KindNotificationEndpointHTTP,
resErr: testPkgResourceError{
name: "missing basic password",
validationErrs: 1,
valFields: []string{fieldNotificationEndpointPassword},
pkgStr: `apiVersion: 0.1.0
kind: Package
meta:
pkgName: pkg_name
pkgVersion: 1
description: pack description
spec:
resources:
- kind: NotificationEndpointHTTP
name: name1
type: basic
url: example.com
username: user
`,
},
},
{
kind: KindNotificationEndpointHTTP,
resErr: testPkgResourceError{
name: "missing basic password and username",
validationErrs: 1,
valFields: []string{fieldNotificationEndpointPassword, fieldNotificationEndpointUsername},
pkgStr: `apiVersion: 0.1.0
kind: Package
meta:
pkgName: pkg_name
pkgVersion: 1
description: pack description
spec:
resources:
- kind: NotificationEndpointHTTP
name: name1
type: basic
url: example.com
`,
},
},
{
kind: KindNotificationEndpointHTTP,
resErr: testPkgResourceError{
name: "missing bearer token",
validationErrs: 1,
valFields: []string{fieldNotificationEndpointToken},
pkgStr: `apiVersion: 0.1.0
kind: Package
meta:
pkgName: pkg_name
pkgVersion: 1
description: pack description
spec:
resources:
- kind: NotificationEndpointHTTP
name: name1
type: bearer
url: example.com
`,
},
},
{
kind: KindNotificationEndpointHTTP,
resErr: testPkgResourceError{
name: "invalid http type",
validationErrs: 1,
valFields: []string{fieldType},
pkgStr: `apiVersion: 0.1.0
kind: Package
meta:
pkgName: pkg_name
pkgVersion: 1
description: pack description
spec:
resources:
- kind: NotificationEndpointHTTP
name: name1
type: threeve
url: example.com
`,
},
},
{
kind: KindNotificationEndpointHTTP,
resErr: testPkgResourceError{
name: "invalid http type",
validationErrs: 1,
valFields: []string{fieldType},
pkgStr: `apiVersion: 0.1.0
kind: Package
meta:
pkgName: pkg_name
pkgVersion: 1
description: pack description
spec:
resources:
- kind: NotificationEndpointHTTP
name: name1
type: threeve
url: example.com
`,
},
},
{
kind: KindNotificationEndpointSlack,
resErr: testPkgResourceError{
name: "duplicate ",
validationErrs: 1,
valFields: []string{fieldName},
pkgStr: `apiVersion: 0.1.0
kind: Package
meta:
pkgName: pkg_name
pkgVersion: 1
description: pack description
spec:
resources:
- kind: NotificationEndpointSlack
name: dupe
url: example.com
- kind: NotificationEndpointSlack
name: dupe
url: example.com
`,
},
},
{
kind: KindNotificationEndpointSlack,
resErr: testPkgResourceError{
name: "invalid status",
validationErrs: 1,
valFields: []string{fieldStatus},
pkgStr: `apiVersion: 0.1.0
kind: Package
meta:
pkgName: pkg_name
pkgVersion: 1
description: pack description
spec:
resources:
- kind: NotificationEndpointSlack
name: dupe
url: example.com
status: rando bad status
`,
},
},
}
for _, tt := range tests {
testPkgErrors(t, tt.kind, tt.resErr)
}
})
})
t.Run("pkg with telegraf and label associations", func(t *testing.T) {
t.Run("with valid fields", func(t *testing.T) {
testfileRunner(t, "testdata/telegraf", func(t *testing.T, pkg *Pkg) {

View File

@ -0,0 +1,91 @@
{
"apiVersion": "0.1.0",
"kind": "Package",
"meta": {
"pkgName": "pkg_name",
"pkgVersion": "1",
"description": "pack description"
},
"spec": {
"resources": [
{
"kind": "Label",
"name": "label_1"
},
{
"kind": "NotificationEndpointSlack",
"name": "slack_notification_endpoint",
"description": "slack desc",
"url": "https://hooks.slack.com/services/bip/piddy/boppidy",
"token": "tokenval",
"status": "active",
"associations": [
{
"kind": "Label",
"name": "label_1"
}
]
},
{
"kind": "NotificationEndpointHTTP",
"name": "http_none_auth_notification_endpoint",
"description": "http none auth desc",
"type": "none",
"url": "https://www.example.com/endpoint/noneauth",
"status": "active",
"associations": [
{
"kind": "Label",
"name": "label_1"
}
]
},
{
"kind": "NotificationEndpointHTTP",
"name": "http_basic_auth_notification_endpoint",
"description": "http basic auth desc",
"type": "basic",
"url": "https://www.example.com/endpoint/basicauth",
"username": "secret username",
"password": "secret password",
"status": "inactive",
"associations": [
{
"kind": "Label",
"name": "label_1"
}
]
},
{
"kind": "NotificationEndpointHTTP",
"name": "http_bearer_auth_notification_endpoint",
"description": "http bearer auth desc",
"type": "bearer",
"url": "https://www.example.com/endpoint/bearerauth",
"token": "secret token",
"associations": [
{
"kind": "Label",
"name": "label_1"
}
]
},
{
"kind": "NotificationEndpointPagerDuty",
"name": "pager_duty_notification_endpoint",
"description": "pager duty desc",
"url": "http://localhost:8080/orgs/7167eb6719fa34e5/alert-history",
"routingKey": "secret routing-key",
"status": "active",
"associations": [
{
"kind": "Label",
"name": "label_1"
}
]
}
]
}
}

View File

@ -0,0 +1,58 @@
apiVersion: 0.1.0
kind: Package
meta:
pkgName: pkg_name
pkgVersion: 1
description: pack description
spec:
resources:
- kind: Label
name: label_1
- kind: NotificationEndpointSlack
name: slack_notification_endpoint
description: slack desc
url: https://hooks.slack.com/services/bip/piddy/boppidy
status: active
token: tokenval
associations:
- kind: Label
name: label_1
- kind: NotificationEndpointHTTP
name: http_none_auth_notification_endpoint
type: none
description: http none auth desc
url: https://www.example.com/endpoint/noneauth
status: active
associations:
- kind: Label
name: label_1
- kind: NotificationEndpointHTTP
name: http_basic_auth_notification_endpoint
description: http basic auth desc
type: basic
url: https://www.example.com/endpoint/basicauth
username: "secret username"
password: "secret password"
status: inactive
associations:
- kind: Label
name: label_1
- kind: NotificationEndpointHTTP
name: http_bearer_auth_notification_endpoint
description: http bearer auth desc
type: bearer
url: https://www.example.com/endpoint/bearerauth
token: "secret token"
associations:
- kind: Label
name: label_1
- kind: NotificationEndpointPagerDuty
name: pager_duty_notification_endpoint
description: pager duty desc
url: http://localhost:8080/orgs/7167eb6719fa34e5/alert-history
routingKey: "secret routing-key"
status: active
associations:
- kind: Label
name: label_1