Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d75506cafe | |||
| 927654a65d | |||
| 5dcd241577 | |||
| 4e2f5436f8 | |||
| 46843cb335 | |||
| b80901cce0 | |||
| 6ee94ef94e | |||
| 6e0d8fd426 | |||
| 335de805b7 |
@@ -2,6 +2,7 @@ package kinds
|
||||
|
||||
import (
|
||||
"github.com/grafana/grafana/apps/alerting/notifications/kinds/v0alpha1"
|
||||
"github.com/grafana/grafana/apps/alerting/notifications/kinds/v0alpha2"
|
||||
)
|
||||
|
||||
receiver: {
|
||||
@@ -24,5 +25,13 @@ receiver: {
|
||||
"spec.title",
|
||||
]
|
||||
}
|
||||
"v0alpha2": {
|
||||
schema: {
|
||||
spec: v0alpha2.ReceiverSpec
|
||||
}
|
||||
selectableFields: [
|
||||
"spec.title",
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,332 @@
|
||||
package v0alpha2
|
||||
|
||||
BaseIntegration: {
|
||||
uid?: string
|
||||
disable_resolve_message?: bool
|
||||
}
|
||||
|
||||
#SecretString: string
|
||||
|
||||
#RedactedSecret: {
|
||||
specified: bool
|
||||
}
|
||||
|
||||
// A string that contain sensitive information.
|
||||
#Secret: string
|
||||
|
||||
AlertmanagerIntegration: BaseIntegration & {
|
||||
url: string
|
||||
basicAuthUser?: string
|
||||
basicAuthPassword?: #Secret
|
||||
}
|
||||
|
||||
DingdingIntegration: BaseIntegration & {
|
||||
url?: string
|
||||
msgType?: string
|
||||
title?: string
|
||||
message?: string
|
||||
}
|
||||
|
||||
DiscordIntegration: BaseIntegration & {
|
||||
url: #Secret
|
||||
title?: string
|
||||
message?: string
|
||||
avatar_url?: string
|
||||
use_discord_username?: bool
|
||||
}
|
||||
|
||||
EmailIntegration: BaseIntegration & {
|
||||
addresses: [...string]
|
||||
singleEmail?: bool
|
||||
message?: string
|
||||
subject?: string
|
||||
}
|
||||
|
||||
GooglechatIntegration: BaseIntegration & {
|
||||
url: #Secret
|
||||
title?: string
|
||||
message?: string
|
||||
}
|
||||
|
||||
JiraIntegration: BaseIntegration & {
|
||||
api_url: string
|
||||
project: string
|
||||
issue_type: string
|
||||
|
||||
summary?: string
|
||||
description?: string
|
||||
labels?: [...string]
|
||||
priority?: string
|
||||
reopen_transition?: string
|
||||
resolve_transition?: string
|
||||
wont_fix_resolution?: string
|
||||
reopen_duration?: string
|
||||
dedup_key_field?: string
|
||||
fields?: {}
|
||||
|
||||
user?: #Secret
|
||||
password?: #Secret
|
||||
api_token?: #Secret
|
||||
}
|
||||
|
||||
KafkaIntegration: BaseIntegration & {
|
||||
kafkaRestProxy: #Secret
|
||||
kafkaTopic: string
|
||||
|
||||
description?: string
|
||||
details?: string
|
||||
username?: string
|
||||
password?: #Secret
|
||||
apiVersion?: string
|
||||
kafkaClusterId?: string
|
||||
}
|
||||
|
||||
LineIntegration: BaseIntegration & {
|
||||
token: #Secret
|
||||
|
||||
title?: string
|
||||
description?: string
|
||||
}
|
||||
|
||||
#TLSConfig: {
|
||||
insecureSkipVerify?: bool
|
||||
caCertificate?: #Secret
|
||||
clientCertificate?: #Secret
|
||||
clientKey?: #Secret
|
||||
}
|
||||
|
||||
MqttIntegration: BaseIntegration & {
|
||||
brokerUrl?: string
|
||||
clientId?: string
|
||||
topic?: string
|
||||
message?: string
|
||||
messageFormat?: string
|
||||
username?: string
|
||||
password?: #Secret
|
||||
qos?: int64
|
||||
retain?: bool
|
||||
tlsConfig?: #TLSConfig
|
||||
}
|
||||
|
||||
OnCallIntegration: BaseIntegration & {
|
||||
url: string
|
||||
|
||||
httpMethod?: string
|
||||
maxAlerts?: int64
|
||||
authorization_scheme?: string
|
||||
authorization_credentials?: #Secret
|
||||
username?: string
|
||||
password?: #Secret
|
||||
title?: string
|
||||
message?: string
|
||||
}
|
||||
|
||||
OpsgenieIntegrationResponder: {
|
||||
id?: string
|
||||
name?: string
|
||||
username?: string
|
||||
type: string
|
||||
}
|
||||
|
||||
OpsgenieIntegration: BaseIntegration & {
|
||||
apiKey: #Secret
|
||||
|
||||
apiUrl?: string
|
||||
message?: string
|
||||
description?: string
|
||||
autoClose?: bool
|
||||
overridePriority?: bool
|
||||
sendTagsAs?: string
|
||||
responders?: [...OpsgenieIntegrationResponder]
|
||||
}
|
||||
|
||||
PagerdutyIntegration: BaseIntegration & {
|
||||
integrationKey: #Secret
|
||||
|
||||
severity?: string
|
||||
class?: string
|
||||
component?: string
|
||||
group?: string
|
||||
summary?: string
|
||||
source?: string
|
||||
client?: string
|
||||
client_url?: string
|
||||
details?: {[string]: string}
|
||||
url?: string
|
||||
}
|
||||
|
||||
PushoverIntegration: BaseIntegration & {
|
||||
userKey: #Secret
|
||||
apiToken: #Secret
|
||||
|
||||
priority?: int64
|
||||
okPriority?: int64
|
||||
retry?: int64
|
||||
expire?: int64
|
||||
device?: string
|
||||
sound?: string
|
||||
okSound?: string
|
||||
title?: string
|
||||
message?: string
|
||||
uploadImage?: bool
|
||||
}
|
||||
|
||||
SensugoIntegration: BaseIntegration & {
|
||||
url: string
|
||||
apikey: #Secret
|
||||
|
||||
entity?: string
|
||||
check?: string
|
||||
namespace?: string
|
||||
handler?: string
|
||||
message?: string
|
||||
}
|
||||
|
||||
#SigV4Config: {
|
||||
region?: string
|
||||
access_key?: #Secret
|
||||
secret_key?: #Secret
|
||||
profile?: string
|
||||
role_arn?: string
|
||||
}
|
||||
|
||||
SnsIntegration: BaseIntegration & {
|
||||
api_url?: string
|
||||
sigv4: #SigV4Config
|
||||
topic_arn?: string
|
||||
phone_number?: string
|
||||
target_arn?: string
|
||||
subject?: string
|
||||
message?: string
|
||||
attributes?: {[string]: string}
|
||||
}
|
||||
|
||||
SlackIntegration: BaseIntegration & {
|
||||
endpointUrl?: string
|
||||
url?: #Secret
|
||||
token?: #Secret
|
||||
recipient?: string
|
||||
text?: string
|
||||
title?: string
|
||||
username?: string
|
||||
icon_emoji?: string
|
||||
icon_url?: string
|
||||
mentionChannel?: string
|
||||
mentionUsers?: string
|
||||
mentionGroups?: string
|
||||
color?: string
|
||||
}
|
||||
|
||||
TelegramIntegration: BaseIntegration & {
|
||||
bottoken: #Secret
|
||||
chatid: string
|
||||
message_thread_id: string
|
||||
|
||||
message?: string
|
||||
parse_mode?: string
|
||||
disable_web_page_preview?: bool
|
||||
protect_content?: bool
|
||||
disable_notifications?: bool
|
||||
}
|
||||
|
||||
TeamsIntegration: BaseIntegration & {
|
||||
url: #Secret
|
||||
|
||||
message?: string
|
||||
title?: string
|
||||
sectiontitle?: string
|
||||
}
|
||||
|
||||
ThreemaIntegration: BaseIntegration & {
|
||||
gateway_id: string
|
||||
recipient_id: string
|
||||
api_secret: #Secret
|
||||
|
||||
title?: string
|
||||
description?: string
|
||||
}
|
||||
|
||||
VictoropsIntegration: BaseIntegration & {
|
||||
url: #Secret
|
||||
|
||||
messageType?: string
|
||||
title?: string
|
||||
description?: string
|
||||
}
|
||||
|
||||
WebexIntegration: BaseIntegration & {
|
||||
bot_token: #Secret
|
||||
|
||||
api_url?: string
|
||||
message?: string
|
||||
room_id?: string
|
||||
}
|
||||
|
||||
#CustomPayload: {
|
||||
template?: string
|
||||
vars?: {[string]: string}
|
||||
}
|
||||
|
||||
#HMACConfig: {
|
||||
secret?: #Secret
|
||||
header: string
|
||||
timestampHeader: string
|
||||
}
|
||||
|
||||
WebhookIntegration: BaseIntegration & {
|
||||
url: string
|
||||
|
||||
httpMethod?: string
|
||||
maxAlerts?: int64
|
||||
authorization_scheme?: string
|
||||
authorization_credentials?: #Secret
|
||||
username?: string
|
||||
password?: #Secret
|
||||
headers?: {[string]: string}
|
||||
title?: string
|
||||
message?: string
|
||||
tlsConfig?: #TLSConfig
|
||||
hmacConfig?: #HMACConfig
|
||||
payload?: #CustomPayload
|
||||
}
|
||||
|
||||
WecomIntegration: BaseIntegration & {
|
||||
endpointUrl?: string
|
||||
url?: #Secret
|
||||
secret?: #Secret
|
||||
agent_id?: string
|
||||
corp_id?: string
|
||||
message?: string
|
||||
title?: string
|
||||
msgtype?: string
|
||||
touser?: string
|
||||
}
|
||||
|
||||
ReceiverSpec: {
|
||||
title: string
|
||||
integrations: {
|
||||
alertmanager?: [...AlertmanagerIntegration]
|
||||
dingding?: [...DingdingIntegration]
|
||||
discord?: [...DiscordIntegration]
|
||||
email?: [...EmailIntegration]
|
||||
googlechat?: [...GooglechatIntegration]
|
||||
jira?: [...JiraIntegration]
|
||||
kafka?: [...KafkaIntegration]
|
||||
line?: [...LineIntegration]
|
||||
mqtt?: [...MqttIntegration]
|
||||
opsgenie?: [...OpsgenieIntegration]
|
||||
pagerduty?: [...PagerdutyIntegration]
|
||||
oncall?: [...OnCallIntegration]
|
||||
pushover?: [...PushoverIntegration]
|
||||
sensugo?: [...SensugoIntegration]
|
||||
slack?: [...SlackIntegration]
|
||||
sns?: [...SnsIntegration]
|
||||
teams?: [...TeamsIntegration]
|
||||
telegram?: [...TelegramIntegration]
|
||||
threema?: [...ThreemaIntegration]
|
||||
victorops?: [...VictoropsIntegration]
|
||||
webhook?: [...WebhookIntegration]
|
||||
wecom?: [...WecomIntegration]
|
||||
webex?: [...WebexIntegration]
|
||||
}
|
||||
}
|
||||
@@ -28,6 +28,13 @@ var appManifestData = app.ManifestData{
|
||||
"spec.title",
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
Name: "v0alpha2",
|
||||
SelectableFields: []string{
|
||||
"spec.title",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
package v0alpha2
|
||||
|
||||
import "k8s.io/apimachinery/pkg/runtime/schema"
|
||||
|
||||
const (
|
||||
// Group is the API group used by all kinds in this package
|
||||
Group = "notifications.alerting.grafana.app"
|
||||
// Version is the API version used by all kinds in this package
|
||||
Version = "v0alpha2"
|
||||
)
|
||||
|
||||
var (
|
||||
// GroupVersion is a schema.GroupVersion consisting of the Group and Version constants for this package
|
||||
GroupVersion = schema.GroupVersion{
|
||||
Group: Group,
|
||||
Version: Version,
|
||||
}
|
||||
)
|
||||
@@ -0,0 +1,139 @@
|
||||
package v0alpha2
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"k8s.io/apimachinery/pkg/fields"
|
||||
"k8s.io/apiserver/pkg/registry/generic"
|
||||
|
||||
"github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/alerting/v0alpha1"
|
||||
)
|
||||
|
||||
func (o *Receiver) GetProvenanceStatus() string {
|
||||
if o == nil || o.Annotations == nil {
|
||||
return ""
|
||||
}
|
||||
s, ok := o.Annotations[v0alpha1.ProvenanceStatusAnnotationKey]
|
||||
if !ok || s == "" {
|
||||
return v0alpha1.ProvenanceStatusNone
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func (o *Receiver) SetProvenanceStatus(status string) {
|
||||
if o.Annotations == nil {
|
||||
o.Annotations = make(map[string]string, 1)
|
||||
}
|
||||
if status == "" {
|
||||
status = v0alpha1.ProvenanceStatusNone
|
||||
}
|
||||
o.Annotations[v0alpha1.ProvenanceStatusAnnotationKey] = status
|
||||
}
|
||||
|
||||
func (o *Receiver) SetAccessControl(action string) {
|
||||
if o.Annotations == nil {
|
||||
o.Annotations = make(map[string]string, 1)
|
||||
}
|
||||
o.Annotations[AccessControlAnnotation(action)] = "true"
|
||||
}
|
||||
|
||||
// AccessControlAnnotation returns the key for the access control annotation for the given action.
|
||||
// Ex. grafana.com/access/canDelete.
|
||||
func AccessControlAnnotation(action string) string {
|
||||
return fmt.Sprintf("%s%s/%s", v0alpha1.InternalPrefix, "access", action)
|
||||
}
|
||||
|
||||
func (o *Receiver) SetInUse(routesCnt int, rules []string) {
|
||||
if o.Annotations == nil {
|
||||
o.Annotations = make(map[string]string, 2)
|
||||
}
|
||||
o.Annotations[InUseAnnotation("routes")] = fmt.Sprintf("%d", routesCnt)
|
||||
o.Annotations[InUseAnnotation("rules")] = fmt.Sprintf("%d", len(rules))
|
||||
}
|
||||
|
||||
func (s *Spec) GetIntegrationsTypes() []string {
|
||||
response := make([]string, 0, 5)
|
||||
if len(s.Integrations.Alertmanager) > 0 {
|
||||
response = append(response, "alertmanager")
|
||||
}
|
||||
if len(s.Integrations.Discord) > 0 {
|
||||
response = append(response, "discord")
|
||||
}
|
||||
if len(s.Integrations.Email) > 0 {
|
||||
response = append(response, "email")
|
||||
}
|
||||
if len(s.Integrations.Googlechat) > 0 {
|
||||
response = append(response, "googlechat")
|
||||
}
|
||||
if len(s.Integrations.Kafka) > 0 {
|
||||
response = append(response, "kafka")
|
||||
}
|
||||
if len(s.Integrations.Line) > 0 {
|
||||
response = append(response, "line")
|
||||
}
|
||||
if len(s.Integrations.Opsgenie) > 0 {
|
||||
response = append(response, "opsgenie")
|
||||
}
|
||||
if len(s.Integrations.Pagerduty) > 0 {
|
||||
response = append(response, "pagerduty")
|
||||
}
|
||||
if len(s.Integrations.Pushover) > 0 {
|
||||
response = append(response, "pushover")
|
||||
}
|
||||
if len(s.Integrations.Sensugo) > 0 {
|
||||
response = append(response, "sensu")
|
||||
}
|
||||
if len(s.Integrations.Slack) > 0 {
|
||||
response = append(response, "slack")
|
||||
}
|
||||
if len(s.Integrations.Teams) > 0 {
|
||||
response = append(response, "teams")
|
||||
}
|
||||
if len(s.Integrations.Telegram) > 0 {
|
||||
response = append(response, "telegram")
|
||||
}
|
||||
if len(s.Integrations.Threema) > 0 {
|
||||
response = append(response, "threema")
|
||||
}
|
||||
if len(s.Integrations.Victorops) > 0 {
|
||||
response = append(response, "victorops")
|
||||
}
|
||||
if len(s.Integrations.Webhook) > 0 {
|
||||
response = append(response, "webhook")
|
||||
}
|
||||
if len(s.Integrations.Wecom) > 0 {
|
||||
response = append(response, "wecom")
|
||||
}
|
||||
return response
|
||||
}
|
||||
|
||||
func (s *Spec) IntegrationsCount() int {
|
||||
return len(s.Integrations.Alertmanager) + len(s.Integrations.Dingding) + len(s.Integrations.Discord) + len(s.Integrations.Email) +
|
||||
len(s.Integrations.Googlechat) + len(s.Integrations.Kafka) + len(s.Integrations.Line) + len(s.Integrations.Opsgenie) +
|
||||
len(s.Integrations.Pagerduty) + len(s.Integrations.Oncall) + len(s.Integrations.Pushover) + len(s.Integrations.Sensugo) +
|
||||
len(s.Integrations.Sns) + len(s.Integrations.Slack) + len(s.Integrations.Teams) + len(s.Integrations.Telegram) +
|
||||
len(s.Integrations.Threema) + len(s.Integrations.Victorops) + len(s.Integrations.Webhook) + len(s.Integrations.Wecom) +
|
||||
len(s.Integrations.Webex) + len(s.Integrations.Mqtt)
|
||||
}
|
||||
|
||||
// InUseAnnotation returns the key for the in-use annotation for the given resource.
|
||||
// Ex. grafana.com/inUse/routes, grafana.com/inUse/rules.
|
||||
func InUseAnnotation(resource string) string {
|
||||
return fmt.Sprintf("%s%s/%s", v0alpha1.InternalPrefix, "inUse", resource)
|
||||
}
|
||||
|
||||
func SelectableFields(obj *Receiver) fields.Set {
|
||||
if obj == nil {
|
||||
return nil
|
||||
}
|
||||
selectable := Schema().SelectableFields()
|
||||
set := make(fields.Set, len(selectable))
|
||||
for _, field := range selectable {
|
||||
f, err := field.FieldValueFunc(obj)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
set[field.FieldSelector] = f
|
||||
}
|
||||
return generic.MergeFieldsSets(generic.ObjectMetaFieldsSet(&obj.ObjectMeta, false), set)
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
//
|
||||
// Code generated by grafana-app-sdk. DO NOT EDIT.
|
||||
//
|
||||
|
||||
package v0alpha2
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
|
||||
"github.com/grafana/grafana-app-sdk/resource"
|
||||
)
|
||||
|
||||
// JSONCodec is an implementation of resource.Codec for kubernetes JSON encoding
|
||||
type JSONCodec struct{}
|
||||
|
||||
// Read reads JSON-encoded bytes from `reader` and unmarshals them into `into`
|
||||
func (*JSONCodec) Read(reader io.Reader, into resource.Object) error {
|
||||
return json.NewDecoder(reader).Decode(into)
|
||||
}
|
||||
|
||||
// Write writes JSON-encoded bytes into `writer` marshaled from `from`
|
||||
func (*JSONCodec) Write(writer io.Writer, from resource.Object) error {
|
||||
return json.NewEncoder(writer).Encode(from)
|
||||
}
|
||||
|
||||
// Interface compliance checks
|
||||
var _ resource.Codec = &JSONCodec{}
|
||||
@@ -0,0 +1,28 @@
|
||||
// Code generated - EDITING IS FUTILE. DO NOT EDIT.
|
||||
|
||||
package v0alpha2
|
||||
|
||||
import (
|
||||
time "time"
|
||||
)
|
||||
|
||||
// metadata contains embedded CommonMetadata and can be extended with custom string fields
|
||||
// TODO: use CommonMetadata instead of redefining here; currently needs to be defined here
|
||||
// without external reference as using the CommonMetadata reference breaks thema codegen.
|
||||
type Metadata struct {
|
||||
UpdateTimestamp time.Time `json:"updateTimestamp"`
|
||||
CreatedBy string `json:"createdBy"`
|
||||
Uid string `json:"uid"`
|
||||
CreationTimestamp time.Time `json:"creationTimestamp"`
|
||||
DeletionTimestamp *time.Time `json:"deletionTimestamp,omitempty"`
|
||||
Finalizers []string `json:"finalizers"`
|
||||
ResourceVersion string `json:"resourceVersion"`
|
||||
Generation int64 `json:"generation"`
|
||||
UpdatedBy string `json:"updatedBy"`
|
||||
Labels map[string]string `json:"labels"`
|
||||
}
|
||||
|
||||
// NewMetadata creates a new Metadata object.
|
||||
func NewMetadata() *Metadata {
|
||||
return &Metadata{}
|
||||
}
|
||||
@@ -0,0 +1,319 @@
|
||||
//
|
||||
// Code generated by grafana-app-sdk. DO NOT EDIT.
|
||||
//
|
||||
|
||||
package v0alpha2
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/grafana/grafana-app-sdk/resource"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"time"
|
||||
)
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type Receiver struct {
|
||||
metav1.TypeMeta `json:",inline" yaml:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata" yaml:"metadata"`
|
||||
|
||||
// Spec is the spec of the Receiver
|
||||
Spec Spec `json:"spec" yaml:"spec"`
|
||||
|
||||
Status Status `json:"status" yaml:"status"`
|
||||
}
|
||||
|
||||
func (o *Receiver) GetSpec() any {
|
||||
return o.Spec
|
||||
}
|
||||
|
||||
func (o *Receiver) SetSpec(spec any) error {
|
||||
cast, ok := spec.(Spec)
|
||||
if !ok {
|
||||
return fmt.Errorf("cannot set spec type %#v, not of type Spec", spec)
|
||||
}
|
||||
o.Spec = cast
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *Receiver) GetSubresources() map[string]any {
|
||||
return map[string]any{
|
||||
"status": o.Status,
|
||||
}
|
||||
}
|
||||
|
||||
func (o *Receiver) GetSubresource(name string) (any, bool) {
|
||||
switch name {
|
||||
case "status":
|
||||
return o.Status, true
|
||||
default:
|
||||
return nil, false
|
||||
}
|
||||
}
|
||||
|
||||
func (o *Receiver) SetSubresource(name string, value any) error {
|
||||
switch name {
|
||||
case "status":
|
||||
cast, ok := value.(Status)
|
||||
if !ok {
|
||||
return fmt.Errorf("cannot set status type %#v, not of type Status", value)
|
||||
}
|
||||
o.Status = cast
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("subresource '%s' does not exist", name)
|
||||
}
|
||||
}
|
||||
|
||||
func (o *Receiver) GetStaticMetadata() resource.StaticMetadata {
|
||||
gvk := o.GroupVersionKind()
|
||||
return resource.StaticMetadata{
|
||||
Name: o.ObjectMeta.Name,
|
||||
Namespace: o.ObjectMeta.Namespace,
|
||||
Group: gvk.Group,
|
||||
Version: gvk.Version,
|
||||
Kind: gvk.Kind,
|
||||
}
|
||||
}
|
||||
|
||||
func (o *Receiver) SetStaticMetadata(metadata resource.StaticMetadata) {
|
||||
o.Name = metadata.Name
|
||||
o.Namespace = metadata.Namespace
|
||||
o.SetGroupVersionKind(schema.GroupVersionKind{
|
||||
Group: metadata.Group,
|
||||
Version: metadata.Version,
|
||||
Kind: metadata.Kind,
|
||||
})
|
||||
}
|
||||
|
||||
func (o *Receiver) GetCommonMetadata() resource.CommonMetadata {
|
||||
dt := o.DeletionTimestamp
|
||||
var deletionTimestamp *time.Time
|
||||
if dt != nil {
|
||||
deletionTimestamp = &dt.Time
|
||||
}
|
||||
// Legacy ExtraFields support
|
||||
extraFields := make(map[string]any)
|
||||
if o.Annotations != nil {
|
||||
extraFields["annotations"] = o.Annotations
|
||||
}
|
||||
if o.ManagedFields != nil {
|
||||
extraFields["managedFields"] = o.ManagedFields
|
||||
}
|
||||
if o.OwnerReferences != nil {
|
||||
extraFields["ownerReferences"] = o.OwnerReferences
|
||||
}
|
||||
return resource.CommonMetadata{
|
||||
UID: string(o.UID),
|
||||
ResourceVersion: o.ResourceVersion,
|
||||
Generation: o.Generation,
|
||||
Labels: o.Labels,
|
||||
CreationTimestamp: o.CreationTimestamp.Time,
|
||||
DeletionTimestamp: deletionTimestamp,
|
||||
Finalizers: o.Finalizers,
|
||||
UpdateTimestamp: o.GetUpdateTimestamp(),
|
||||
CreatedBy: o.GetCreatedBy(),
|
||||
UpdatedBy: o.GetUpdatedBy(),
|
||||
ExtraFields: extraFields,
|
||||
}
|
||||
}
|
||||
|
||||
func (o *Receiver) SetCommonMetadata(metadata resource.CommonMetadata) {
|
||||
o.UID = types.UID(metadata.UID)
|
||||
o.ResourceVersion = metadata.ResourceVersion
|
||||
o.Generation = metadata.Generation
|
||||
o.Labels = metadata.Labels
|
||||
o.CreationTimestamp = metav1.NewTime(metadata.CreationTimestamp)
|
||||
if metadata.DeletionTimestamp != nil {
|
||||
dt := metav1.NewTime(*metadata.DeletionTimestamp)
|
||||
o.DeletionTimestamp = &dt
|
||||
} else {
|
||||
o.DeletionTimestamp = nil
|
||||
}
|
||||
o.Finalizers = metadata.Finalizers
|
||||
if o.Annotations == nil {
|
||||
o.Annotations = make(map[string]string)
|
||||
}
|
||||
if !metadata.UpdateTimestamp.IsZero() {
|
||||
o.SetUpdateTimestamp(metadata.UpdateTimestamp)
|
||||
}
|
||||
if metadata.CreatedBy != "" {
|
||||
o.SetCreatedBy(metadata.CreatedBy)
|
||||
}
|
||||
if metadata.UpdatedBy != "" {
|
||||
o.SetUpdatedBy(metadata.UpdatedBy)
|
||||
}
|
||||
// Legacy support for setting Annotations, ManagedFields, and OwnerReferences via ExtraFields
|
||||
if metadata.ExtraFields != nil {
|
||||
if annotations, ok := metadata.ExtraFields["annotations"]; ok {
|
||||
if cast, ok := annotations.(map[string]string); ok {
|
||||
o.Annotations = cast
|
||||
}
|
||||
}
|
||||
if managedFields, ok := metadata.ExtraFields["managedFields"]; ok {
|
||||
if cast, ok := managedFields.([]metav1.ManagedFieldsEntry); ok {
|
||||
o.ManagedFields = cast
|
||||
}
|
||||
}
|
||||
if ownerReferences, ok := metadata.ExtraFields["ownerReferences"]; ok {
|
||||
if cast, ok := ownerReferences.([]metav1.OwnerReference); ok {
|
||||
o.OwnerReferences = cast
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (o *Receiver) GetCreatedBy() string {
|
||||
if o.ObjectMeta.Annotations == nil {
|
||||
o.ObjectMeta.Annotations = make(map[string]string)
|
||||
}
|
||||
|
||||
return o.ObjectMeta.Annotations["grafana.com/createdBy"]
|
||||
}
|
||||
|
||||
func (o *Receiver) SetCreatedBy(createdBy string) {
|
||||
if o.ObjectMeta.Annotations == nil {
|
||||
o.ObjectMeta.Annotations = make(map[string]string)
|
||||
}
|
||||
|
||||
o.ObjectMeta.Annotations["grafana.com/createdBy"] = createdBy
|
||||
}
|
||||
|
||||
func (o *Receiver) GetUpdateTimestamp() time.Time {
|
||||
if o.ObjectMeta.Annotations == nil {
|
||||
o.ObjectMeta.Annotations = make(map[string]string)
|
||||
}
|
||||
|
||||
parsed, _ := time.Parse(time.RFC3339, o.ObjectMeta.Annotations["grafana.com/updateTimestamp"])
|
||||
return parsed
|
||||
}
|
||||
|
||||
func (o *Receiver) SetUpdateTimestamp(updateTimestamp time.Time) {
|
||||
if o.ObjectMeta.Annotations == nil {
|
||||
o.ObjectMeta.Annotations = make(map[string]string)
|
||||
}
|
||||
|
||||
o.ObjectMeta.Annotations["grafana.com/updateTimestamp"] = updateTimestamp.Format(time.RFC3339)
|
||||
}
|
||||
|
||||
func (o *Receiver) GetUpdatedBy() string {
|
||||
if o.ObjectMeta.Annotations == nil {
|
||||
o.ObjectMeta.Annotations = make(map[string]string)
|
||||
}
|
||||
|
||||
return o.ObjectMeta.Annotations["grafana.com/updatedBy"]
|
||||
}
|
||||
|
||||
func (o *Receiver) SetUpdatedBy(updatedBy string) {
|
||||
if o.ObjectMeta.Annotations == nil {
|
||||
o.ObjectMeta.Annotations = make(map[string]string)
|
||||
}
|
||||
|
||||
o.ObjectMeta.Annotations["grafana.com/updatedBy"] = updatedBy
|
||||
}
|
||||
|
||||
func (o *Receiver) Copy() resource.Object {
|
||||
return resource.CopyObject(o)
|
||||
}
|
||||
|
||||
func (o *Receiver) DeepCopyObject() runtime.Object {
|
||||
return o.Copy()
|
||||
}
|
||||
|
||||
func (o *Receiver) DeepCopy() *Receiver {
|
||||
cpy := &Receiver{}
|
||||
o.DeepCopyInto(cpy)
|
||||
return cpy
|
||||
}
|
||||
|
||||
func (o *Receiver) DeepCopyInto(dst *Receiver) {
|
||||
dst.TypeMeta.APIVersion = o.TypeMeta.APIVersion
|
||||
dst.TypeMeta.Kind = o.TypeMeta.Kind
|
||||
o.ObjectMeta.DeepCopyInto(&dst.ObjectMeta)
|
||||
o.Spec.DeepCopyInto(&dst.Spec)
|
||||
o.Status.DeepCopyInto(&dst.Status)
|
||||
}
|
||||
|
||||
// Interface compliance compile-time check
|
||||
var _ resource.Object = &Receiver{}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type ReceiverList struct {
|
||||
metav1.TypeMeta `json:",inline" yaml:",inline"`
|
||||
metav1.ListMeta `json:"metadata" yaml:"metadata"`
|
||||
Items []Receiver `json:"items" yaml:"items"`
|
||||
}
|
||||
|
||||
func (o *ReceiverList) DeepCopyObject() runtime.Object {
|
||||
return o.Copy()
|
||||
}
|
||||
|
||||
func (o *ReceiverList) Copy() resource.ListObject {
|
||||
cpy := &ReceiverList{
|
||||
TypeMeta: o.TypeMeta,
|
||||
Items: make([]Receiver, len(o.Items)),
|
||||
}
|
||||
o.ListMeta.DeepCopyInto(&cpy.ListMeta)
|
||||
for i := 0; i < len(o.Items); i++ {
|
||||
if item, ok := o.Items[i].Copy().(*Receiver); ok {
|
||||
cpy.Items[i] = *item
|
||||
}
|
||||
}
|
||||
return cpy
|
||||
}
|
||||
|
||||
func (o *ReceiverList) GetItems() []resource.Object {
|
||||
items := make([]resource.Object, len(o.Items))
|
||||
for i := 0; i < len(o.Items); i++ {
|
||||
items[i] = &o.Items[i]
|
||||
}
|
||||
return items
|
||||
}
|
||||
|
||||
func (o *ReceiverList) SetItems(items []resource.Object) {
|
||||
o.Items = make([]Receiver, len(items))
|
||||
for i := 0; i < len(items); i++ {
|
||||
o.Items[i] = *items[i].(*Receiver)
|
||||
}
|
||||
}
|
||||
|
||||
func (o *ReceiverList) DeepCopy() *ReceiverList {
|
||||
cpy := &ReceiverList{}
|
||||
o.DeepCopyInto(cpy)
|
||||
return cpy
|
||||
}
|
||||
|
||||
func (o *ReceiverList) DeepCopyInto(dst *ReceiverList) {
|
||||
resource.CopyObjectInto(dst, o)
|
||||
}
|
||||
|
||||
// Interface compliance compile-time check
|
||||
var _ resource.ListObject = &ReceiverList{}
|
||||
|
||||
// Copy methods for all subresource types
|
||||
|
||||
// DeepCopy creates a full deep copy of Spec
|
||||
func (s *Spec) DeepCopy() *Spec {
|
||||
cpy := &Spec{}
|
||||
s.DeepCopyInto(cpy)
|
||||
return cpy
|
||||
}
|
||||
|
||||
// DeepCopyInto deep copies Spec into another Spec object
|
||||
func (s *Spec) DeepCopyInto(dst *Spec) {
|
||||
resource.CopyObjectInto(dst, s)
|
||||
}
|
||||
|
||||
// DeepCopy creates a full deep copy of Status
|
||||
func (s *Status) DeepCopy() *Status {
|
||||
cpy := &Status{}
|
||||
s.DeepCopyInto(cpy)
|
||||
return cpy
|
||||
}
|
||||
|
||||
// DeepCopyInto deep copies Status into another Status object
|
||||
func (s *Status) DeepCopyInto(dst *Status) {
|
||||
resource.CopyObjectInto(dst, s)
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
//
|
||||
// Code generated by grafana-app-sdk. DO NOT EDIT.
|
||||
//
|
||||
|
||||
package v0alpha2
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/grafana/grafana-app-sdk/resource"
|
||||
)
|
||||
|
||||
// schema is unexported to prevent accidental overwrites
|
||||
var (
|
||||
schemaReceiver = resource.NewSimpleSchema("notifications.alerting.grafana.app", "v0alpha2", &Receiver{}, &ReceiverList{}, resource.WithKind("Receiver"),
|
||||
resource.WithPlural("receivers"), resource.WithScope(resource.NamespacedScope), resource.WithSelectableFields([]resource.SelectableField{resource.SelectableField{
|
||||
FieldSelector: "spec.title",
|
||||
FieldValueFunc: func(o resource.Object) (string, error) {
|
||||
cast, ok := o.(*Receiver)
|
||||
if !ok {
|
||||
return "", fmt.Errorf("provided object must be of type *Receiver")
|
||||
}
|
||||
return cast.Spec.Title, nil
|
||||
},
|
||||
},
|
||||
}))
|
||||
kindReceiver = resource.Kind{
|
||||
Schema: schemaReceiver,
|
||||
Codecs: map[resource.KindEncoding]resource.Codec{
|
||||
resource.KindEncodingJSON: &JSONCodec{},
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
// Kind returns a resource.Kind for this Schema with a JSON codec
|
||||
func Kind() resource.Kind {
|
||||
return kindReceiver
|
||||
}
|
||||
|
||||
// Schema returns a resource.SimpleSchema representation of Receiver
|
||||
func Schema() *resource.SimpleSchema {
|
||||
return schemaReceiver
|
||||
}
|
||||
|
||||
// Interface compliance checks
|
||||
var _ resource.Schema = kindReceiver
|
||||
@@ -0,0 +1,541 @@
|
||||
// Code generated - EDITING IS FUTILE. DO NOT EDIT.
|
||||
|
||||
package v0alpha2
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type AlertmanagerIntegration struct {
|
||||
Uid *string `json:"uid,omitempty"`
|
||||
Url string `json:"url"`
|
||||
BasicAuthUser *string `json:"basicAuthUser,omitempty"`
|
||||
DisableResolveMessage *bool `json:"disable_resolve_message,omitempty"`
|
||||
BasicAuthPassword *Secret `json:"basicAuthPassword,omitempty"`
|
||||
}
|
||||
|
||||
// NewAlertmanagerIntegration creates a new AlertmanagerIntegration object.
|
||||
func NewAlertmanagerIntegration() *AlertmanagerIntegration {
|
||||
return &AlertmanagerIntegration{}
|
||||
}
|
||||
|
||||
// A string that contain sensitive information.
|
||||
// +k8s:openapi-gen=true
|
||||
type Secret string
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type DingdingIntegration struct {
|
||||
Uid *string `json:"uid,omitempty"`
|
||||
Url *string `json:"url,omitempty"`
|
||||
MsgType *string `json:"msgType,omitempty"`
|
||||
Title *string `json:"title,omitempty"`
|
||||
DisableResolveMessage *bool `json:"disable_resolve_message,omitempty"`
|
||||
Message *string `json:"message,omitempty"`
|
||||
}
|
||||
|
||||
// NewDingdingIntegration creates a new DingdingIntegration object.
|
||||
func NewDingdingIntegration() *DingdingIntegration {
|
||||
return &DingdingIntegration{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type DiscordIntegration struct {
|
||||
Uid *string `json:"uid,omitempty"`
|
||||
Url Secret `json:"url"`
|
||||
Title *string `json:"title,omitempty"`
|
||||
Message *string `json:"message,omitempty"`
|
||||
AvatarUrl *string `json:"avatar_url,omitempty"`
|
||||
DisableResolveMessage *bool `json:"disable_resolve_message,omitempty"`
|
||||
UseDiscordUsername *bool `json:"use_discord_username,omitempty"`
|
||||
}
|
||||
|
||||
// NewDiscordIntegration creates a new DiscordIntegration object.
|
||||
func NewDiscordIntegration() *DiscordIntegration {
|
||||
return &DiscordIntegration{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type EmailIntegration struct {
|
||||
Uid *string `json:"uid,omitempty"`
|
||||
Addresses []string `json:"addresses"`
|
||||
SingleEmail *bool `json:"singleEmail,omitempty"`
|
||||
Message *string `json:"message,omitempty"`
|
||||
DisableResolveMessage *bool `json:"disable_resolve_message,omitempty"`
|
||||
Subject *string `json:"subject,omitempty"`
|
||||
}
|
||||
|
||||
// NewEmailIntegration creates a new EmailIntegration object.
|
||||
func NewEmailIntegration() *EmailIntegration {
|
||||
return &EmailIntegration{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type GooglechatIntegration struct {
|
||||
Uid *string `json:"uid,omitempty"`
|
||||
Url Secret `json:"url"`
|
||||
Title *string `json:"title,omitempty"`
|
||||
DisableResolveMessage *bool `json:"disable_resolve_message,omitempty"`
|
||||
Message *string `json:"message,omitempty"`
|
||||
}
|
||||
|
||||
// NewGooglechatIntegration creates a new GooglechatIntegration object.
|
||||
func NewGooglechatIntegration() *GooglechatIntegration {
|
||||
return &GooglechatIntegration{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type JiraIntegration struct {
|
||||
Uid *string `json:"uid,omitempty"`
|
||||
ApiUrl string `json:"api_url"`
|
||||
Project string `json:"project"`
|
||||
IssueType string `json:"issue_type"`
|
||||
Summary *string `json:"summary,omitempty"`
|
||||
Description *string `json:"description,omitempty"`
|
||||
Labels []string `json:"labels,omitempty"`
|
||||
Priority *string `json:"priority,omitempty"`
|
||||
ReopenTransition *string `json:"reopen_transition,omitempty"`
|
||||
ResolveTransition *string `json:"resolve_transition,omitempty"`
|
||||
WontFixResolution *string `json:"wont_fix_resolution,omitempty"`
|
||||
ReopenDuration *string `json:"reopen_duration,omitempty"`
|
||||
DedupKeyField *string `json:"dedup_key_field,omitempty"`
|
||||
Fields interface{} `json:"fields,omitempty"`
|
||||
User *Secret `json:"user,omitempty"`
|
||||
Password *Secret `json:"password,omitempty"`
|
||||
DisableResolveMessage *bool `json:"disable_resolve_message,omitempty"`
|
||||
ApiToken *Secret `json:"api_token,omitempty"`
|
||||
}
|
||||
|
||||
// NewJiraIntegration creates a new JiraIntegration object.
|
||||
func NewJiraIntegration() *JiraIntegration {
|
||||
return &JiraIntegration{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type KafkaIntegration struct {
|
||||
Uid *string `json:"uid,omitempty"`
|
||||
KafkaRestProxy Secret `json:"kafkaRestProxy"`
|
||||
KafkaTopic string `json:"kafkaTopic"`
|
||||
Description *string `json:"description,omitempty"`
|
||||
Details *string `json:"details,omitempty"`
|
||||
Username *string `json:"username,omitempty"`
|
||||
Password *Secret `json:"password,omitempty"`
|
||||
ApiVersion *string `json:"apiVersion,omitempty"`
|
||||
DisableResolveMessage *bool `json:"disable_resolve_message,omitempty"`
|
||||
KafkaClusterId *string `json:"kafkaClusterId,omitempty"`
|
||||
}
|
||||
|
||||
// NewKafkaIntegration creates a new KafkaIntegration object.
|
||||
func NewKafkaIntegration() *KafkaIntegration {
|
||||
return &KafkaIntegration{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type LineIntegration struct {
|
||||
Uid *string `json:"uid,omitempty"`
|
||||
Token Secret `json:"token"`
|
||||
Title *string `json:"title,omitempty"`
|
||||
DisableResolveMessage *bool `json:"disable_resolve_message,omitempty"`
|
||||
Description *string `json:"description,omitempty"`
|
||||
}
|
||||
|
||||
// NewLineIntegration creates a new LineIntegration object.
|
||||
func NewLineIntegration() *LineIntegration {
|
||||
return &LineIntegration{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type MqttIntegration struct {
|
||||
Uid *string `json:"uid,omitempty"`
|
||||
BrokerUrl *string `json:"brokerUrl,omitempty"`
|
||||
ClientId *string `json:"clientId,omitempty"`
|
||||
Topic *string `json:"topic,omitempty"`
|
||||
Message *string `json:"message,omitempty"`
|
||||
MessageFormat *string `json:"messageFormat,omitempty"`
|
||||
Username *string `json:"username,omitempty"`
|
||||
Password *Secret `json:"password,omitempty"`
|
||||
Qos *int64 `json:"qos,omitempty"`
|
||||
Retain *bool `json:"retain,omitempty"`
|
||||
DisableResolveMessage *bool `json:"disable_resolve_message,omitempty"`
|
||||
TlsConfig *TLSConfig `json:"tlsConfig,omitempty"`
|
||||
}
|
||||
|
||||
// NewMqttIntegration creates a new MqttIntegration object.
|
||||
func NewMqttIntegration() *MqttIntegration {
|
||||
return &MqttIntegration{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type TLSConfig struct {
|
||||
InsecureSkipVerify *bool `json:"insecureSkipVerify,omitempty"`
|
||||
CaCertificate *Secret `json:"caCertificate,omitempty"`
|
||||
ClientCertificate *Secret `json:"clientCertificate,omitempty"`
|
||||
ClientKey *Secret `json:"clientKey,omitempty"`
|
||||
}
|
||||
|
||||
// NewTLSConfig creates a new TLSConfig object.
|
||||
func NewTLSConfig() *TLSConfig {
|
||||
return &TLSConfig{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type OpsgenieIntegration struct {
|
||||
Uid *string `json:"uid,omitempty"`
|
||||
ApiKey Secret `json:"apiKey"`
|
||||
ApiUrl *string `json:"apiUrl,omitempty"`
|
||||
Message *string `json:"message,omitempty"`
|
||||
Description *string `json:"description,omitempty"`
|
||||
AutoClose *bool `json:"autoClose,omitempty"`
|
||||
OverridePriority *bool `json:"overridePriority,omitempty"`
|
||||
SendTagsAs *string `json:"sendTagsAs,omitempty"`
|
||||
DisableResolveMessage *bool `json:"disable_resolve_message,omitempty"`
|
||||
Responders []OpsgenieIntegrationResponder `json:"responders,omitempty"`
|
||||
}
|
||||
|
||||
// NewOpsgenieIntegration creates a new OpsgenieIntegration object.
|
||||
func NewOpsgenieIntegration() *OpsgenieIntegration {
|
||||
return &OpsgenieIntegration{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type OpsgenieIntegrationResponder struct {
|
||||
Id *string `json:"id,omitempty"`
|
||||
Name *string `json:"name,omitempty"`
|
||||
Username *string `json:"username,omitempty"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
// NewOpsgenieIntegrationResponder creates a new OpsgenieIntegrationResponder object.
|
||||
func NewOpsgenieIntegrationResponder() *OpsgenieIntegrationResponder {
|
||||
return &OpsgenieIntegrationResponder{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type PagerdutyIntegration struct {
|
||||
Uid *string `json:"uid,omitempty"`
|
||||
IntegrationKey Secret `json:"integrationKey"`
|
||||
Severity *string `json:"severity,omitempty"`
|
||||
Class *string `json:"class,omitempty"`
|
||||
Component *string `json:"component,omitempty"`
|
||||
Group *string `json:"group,omitempty"`
|
||||
Summary *string `json:"summary,omitempty"`
|
||||
Source *string `json:"source,omitempty"`
|
||||
Client *string `json:"client,omitempty"`
|
||||
ClientUrl *string `json:"client_url,omitempty"`
|
||||
Details map[string]string `json:"details,omitempty"`
|
||||
DisableResolveMessage *bool `json:"disable_resolve_message,omitempty"`
|
||||
Url *string `json:"url,omitempty"`
|
||||
}
|
||||
|
||||
// NewPagerdutyIntegration creates a new PagerdutyIntegration object.
|
||||
func NewPagerdutyIntegration() *PagerdutyIntegration {
|
||||
return &PagerdutyIntegration{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type OnCallIntegration struct {
|
||||
Uid *string `json:"uid,omitempty"`
|
||||
Url string `json:"url"`
|
||||
HttpMethod *string `json:"httpMethod,omitempty"`
|
||||
MaxAlerts *int64 `json:"maxAlerts,omitempty"`
|
||||
AuthorizationScheme *string `json:"authorization_scheme,omitempty"`
|
||||
AuthorizationCredentials *Secret `json:"authorization_credentials,omitempty"`
|
||||
Username *string `json:"username,omitempty"`
|
||||
Password *Secret `json:"password,omitempty"`
|
||||
Title *string `json:"title,omitempty"`
|
||||
DisableResolveMessage *bool `json:"disable_resolve_message,omitempty"`
|
||||
Message *string `json:"message,omitempty"`
|
||||
}
|
||||
|
||||
// NewOnCallIntegration creates a new OnCallIntegration object.
|
||||
func NewOnCallIntegration() *OnCallIntegration {
|
||||
return &OnCallIntegration{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type PushoverIntegration struct {
|
||||
Uid *string `json:"uid,omitempty"`
|
||||
UserKey Secret `json:"userKey"`
|
||||
ApiToken Secret `json:"apiToken"`
|
||||
Priority *int64 `json:"priority,omitempty"`
|
||||
OkPriority *int64 `json:"okPriority,omitempty"`
|
||||
Retry *int64 `json:"retry,omitempty"`
|
||||
Expire *int64 `json:"expire,omitempty"`
|
||||
Device *string `json:"device,omitempty"`
|
||||
Sound *string `json:"sound,omitempty"`
|
||||
OkSound *string `json:"okSound,omitempty"`
|
||||
Title *string `json:"title,omitempty"`
|
||||
Message *string `json:"message,omitempty"`
|
||||
DisableResolveMessage *bool `json:"disable_resolve_message,omitempty"`
|
||||
UploadImage *bool `json:"uploadImage,omitempty"`
|
||||
}
|
||||
|
||||
// NewPushoverIntegration creates a new PushoverIntegration object.
|
||||
func NewPushoverIntegration() *PushoverIntegration {
|
||||
return &PushoverIntegration{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type SensugoIntegration struct {
|
||||
Uid *string `json:"uid,omitempty"`
|
||||
Url string `json:"url"`
|
||||
Apikey Secret `json:"apikey"`
|
||||
Entity *string `json:"entity,omitempty"`
|
||||
Check *string `json:"check,omitempty"`
|
||||
Namespace *string `json:"namespace,omitempty"`
|
||||
Handler *string `json:"handler,omitempty"`
|
||||
DisableResolveMessage *bool `json:"disable_resolve_message,omitempty"`
|
||||
Message *string `json:"message,omitempty"`
|
||||
}
|
||||
|
||||
// NewSensugoIntegration creates a new SensugoIntegration object.
|
||||
func NewSensugoIntegration() *SensugoIntegration {
|
||||
return &SensugoIntegration{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type SlackIntegration struct {
|
||||
Uid *string `json:"uid,omitempty"`
|
||||
EndpointUrl *string `json:"endpointUrl,omitempty"`
|
||||
Url *Secret `json:"url,omitempty"`
|
||||
Token *Secret `json:"token,omitempty"`
|
||||
Recipient *string `json:"recipient,omitempty"`
|
||||
Text *string `json:"text,omitempty"`
|
||||
Title *string `json:"title,omitempty"`
|
||||
Username *string `json:"username,omitempty"`
|
||||
IconEmoji *string `json:"icon_emoji,omitempty"`
|
||||
IconUrl *string `json:"icon_url,omitempty"`
|
||||
MentionChannel *string `json:"mentionChannel,omitempty"`
|
||||
MentionUsers *string `json:"mentionUsers,omitempty"`
|
||||
MentionGroups *string `json:"mentionGroups,omitempty"`
|
||||
DisableResolveMessage *bool `json:"disable_resolve_message,omitempty"`
|
||||
Color *string `json:"color,omitempty"`
|
||||
}
|
||||
|
||||
// NewSlackIntegration creates a new SlackIntegration object.
|
||||
func NewSlackIntegration() *SlackIntegration {
|
||||
return &SlackIntegration{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type SnsIntegration struct {
|
||||
Uid *string `json:"uid,omitempty"`
|
||||
ApiUrl *string `json:"api_url,omitempty"`
|
||||
Sigv4 SigV4Config `json:"sigv4"`
|
||||
TopicArn *string `json:"topic_arn,omitempty"`
|
||||
PhoneNumber *string `json:"phone_number,omitempty"`
|
||||
TargetArn *string `json:"target_arn,omitempty"`
|
||||
Subject *string `json:"subject,omitempty"`
|
||||
Message *string `json:"message,omitempty"`
|
||||
DisableResolveMessage *bool `json:"disable_resolve_message,omitempty"`
|
||||
Attributes map[string]string `json:"attributes,omitempty"`
|
||||
}
|
||||
|
||||
// NewSnsIntegration creates a new SnsIntegration object.
|
||||
func NewSnsIntegration() *SnsIntegration {
|
||||
return &SnsIntegration{
|
||||
Sigv4: *NewSigV4Config(),
|
||||
}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type SigV4Config struct {
|
||||
Region *string `json:"region,omitempty"`
|
||||
AccessKey *Secret `json:"access_key,omitempty"`
|
||||
SecretKey *Secret `json:"secret_key,omitempty"`
|
||||
Profile *string `json:"profile,omitempty"`
|
||||
RoleArn *string `json:"role_arn,omitempty"`
|
||||
}
|
||||
|
||||
// NewSigV4Config creates a new SigV4Config object.
|
||||
func NewSigV4Config() *SigV4Config {
|
||||
return &SigV4Config{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type TeamsIntegration struct {
|
||||
Uid *string `json:"uid,omitempty"`
|
||||
Url Secret `json:"url"`
|
||||
Message *string `json:"message,omitempty"`
|
||||
Title *string `json:"title,omitempty"`
|
||||
DisableResolveMessage *bool `json:"disable_resolve_message,omitempty"`
|
||||
Sectiontitle *string `json:"sectiontitle,omitempty"`
|
||||
}
|
||||
|
||||
// NewTeamsIntegration creates a new TeamsIntegration object.
|
||||
func NewTeamsIntegration() *TeamsIntegration {
|
||||
return &TeamsIntegration{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type TelegramIntegration struct {
|
||||
Uid *string `json:"uid,omitempty"`
|
||||
Bottoken Secret `json:"bottoken"`
|
||||
Chatid string `json:"chatid"`
|
||||
MessageThreadId string `json:"message_thread_id"`
|
||||
Message *string `json:"message,omitempty"`
|
||||
ParseMode *string `json:"parse_mode,omitempty"`
|
||||
DisableWebPagePreview *bool `json:"disable_web_page_preview,omitempty"`
|
||||
ProtectContent *bool `json:"protect_content,omitempty"`
|
||||
DisableResolveMessage *bool `json:"disable_resolve_message,omitempty"`
|
||||
DisableNotifications *bool `json:"disable_notifications,omitempty"`
|
||||
}
|
||||
|
||||
// NewTelegramIntegration creates a new TelegramIntegration object.
|
||||
func NewTelegramIntegration() *TelegramIntegration {
|
||||
return &TelegramIntegration{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type ThreemaIntegration struct {
|
||||
Uid *string `json:"uid,omitempty"`
|
||||
GatewayId string `json:"gateway_id"`
|
||||
RecipientId string `json:"recipient_id"`
|
||||
ApiSecret Secret `json:"api_secret"`
|
||||
Title *string `json:"title,omitempty"`
|
||||
DisableResolveMessage *bool `json:"disable_resolve_message,omitempty"`
|
||||
Description *string `json:"description,omitempty"`
|
||||
}
|
||||
|
||||
// NewThreemaIntegration creates a new ThreemaIntegration object.
|
||||
func NewThreemaIntegration() *ThreemaIntegration {
|
||||
return &ThreemaIntegration{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type VictoropsIntegration struct {
|
||||
Uid *string `json:"uid,omitempty"`
|
||||
Url Secret `json:"url"`
|
||||
MessageType *string `json:"messageType,omitempty"`
|
||||
Title *string `json:"title,omitempty"`
|
||||
DisableResolveMessage *bool `json:"disable_resolve_message,omitempty"`
|
||||
Description *string `json:"description,omitempty"`
|
||||
}
|
||||
|
||||
// NewVictoropsIntegration creates a new VictoropsIntegration object.
|
||||
func NewVictoropsIntegration() *VictoropsIntegration {
|
||||
return &VictoropsIntegration{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type WebhookIntegration struct {
|
||||
Uid *string `json:"uid,omitempty"`
|
||||
Url string `json:"url"`
|
||||
HttpMethod *string `json:"httpMethod,omitempty"`
|
||||
MaxAlerts *int64 `json:"maxAlerts,omitempty"`
|
||||
AuthorizationScheme *string `json:"authorization_scheme,omitempty"`
|
||||
AuthorizationCredentials *Secret `json:"authorization_credentials,omitempty"`
|
||||
Username *string `json:"username,omitempty"`
|
||||
Password *Secret `json:"password,omitempty"`
|
||||
Headers map[string]string `json:"headers,omitempty"`
|
||||
Title *string `json:"title,omitempty"`
|
||||
Message *string `json:"message,omitempty"`
|
||||
TlsConfig *TLSConfig `json:"tlsConfig,omitempty"`
|
||||
HmacConfig *HMACConfig `json:"hmacConfig,omitempty"`
|
||||
DisableResolveMessage *bool `json:"disable_resolve_message,omitempty"`
|
||||
Payload *CustomPayload `json:"payload,omitempty"`
|
||||
}
|
||||
|
||||
// NewWebhookIntegration creates a new WebhookIntegration object.
|
||||
func NewWebhookIntegration() *WebhookIntegration {
|
||||
return &WebhookIntegration{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type HMACConfig struct {
|
||||
Secret *Secret `json:"secret,omitempty"`
|
||||
Header string `json:"header"`
|
||||
TimestampHeader string `json:"timestampHeader"`
|
||||
}
|
||||
|
||||
// NewHMACConfig creates a new HMACConfig object.
|
||||
func NewHMACConfig() *HMACConfig {
|
||||
return &HMACConfig{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type CustomPayload struct {
|
||||
Template *string `json:"template,omitempty"`
|
||||
Vars map[string]string `json:"vars,omitempty"`
|
||||
}
|
||||
|
||||
// NewCustomPayload creates a new CustomPayload object.
|
||||
func NewCustomPayload() *CustomPayload {
|
||||
return &CustomPayload{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type WecomIntegration struct {
|
||||
Uid *string `json:"uid,omitempty"`
|
||||
EndpointUrl *string `json:"endpointUrl,omitempty"`
|
||||
Url *Secret `json:"url,omitempty"`
|
||||
Secret *Secret `json:"secret,omitempty"`
|
||||
AgentId *string `json:"agent_id,omitempty"`
|
||||
CorpId *string `json:"corp_id,omitempty"`
|
||||
Message *string `json:"message,omitempty"`
|
||||
Title *string `json:"title,omitempty"`
|
||||
Msgtype *string `json:"msgtype,omitempty"`
|
||||
DisableResolveMessage *bool `json:"disable_resolve_message,omitempty"`
|
||||
Touser *string `json:"touser,omitempty"`
|
||||
}
|
||||
|
||||
// NewWecomIntegration creates a new WecomIntegration object.
|
||||
func NewWecomIntegration() *WecomIntegration {
|
||||
return &WecomIntegration{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type WebexIntegration struct {
|
||||
Uid *string `json:"uid,omitempty"`
|
||||
BotToken Secret `json:"bot_token"`
|
||||
ApiUrl *string `json:"api_url,omitempty"`
|
||||
Message *string `json:"message,omitempty"`
|
||||
DisableResolveMessage *bool `json:"disable_resolve_message,omitempty"`
|
||||
RoomId *string `json:"room_id,omitempty"`
|
||||
}
|
||||
|
||||
// NewWebexIntegration creates a new WebexIntegration object.
|
||||
func NewWebexIntegration() *WebexIntegration {
|
||||
return &WebexIntegration{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type Spec struct {
|
||||
Title string `json:"title"`
|
||||
Integrations V0alpha2SpecIntegrations `json:"integrations"`
|
||||
}
|
||||
|
||||
// NewSpec creates a new Spec object.
|
||||
func NewSpec() *Spec {
|
||||
return &Spec{
|
||||
Integrations: *NewV0alpha2SpecIntegrations(),
|
||||
}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type V0alpha2SpecIntegrations struct {
|
||||
Alertmanager []AlertmanagerIntegration `json:"alertmanager,omitempty"`
|
||||
Dingding []DingdingIntegration `json:"dingding,omitempty"`
|
||||
Discord []DiscordIntegration `json:"discord,omitempty"`
|
||||
Email []EmailIntegration `json:"email,omitempty"`
|
||||
Googlechat []GooglechatIntegration `json:"googlechat,omitempty"`
|
||||
Jira []JiraIntegration `json:"jira,omitempty"`
|
||||
Kafka []KafkaIntegration `json:"kafka,omitempty"`
|
||||
Line []LineIntegration `json:"line,omitempty"`
|
||||
Mqtt []MqttIntegration `json:"mqtt,omitempty"`
|
||||
Opsgenie []OpsgenieIntegration `json:"opsgenie,omitempty"`
|
||||
Pagerduty []PagerdutyIntegration `json:"pagerduty,omitempty"`
|
||||
Oncall []OnCallIntegration `json:"oncall,omitempty"`
|
||||
Pushover []PushoverIntegration `json:"pushover,omitempty"`
|
||||
Sensugo []SensugoIntegration `json:"sensugo,omitempty"`
|
||||
Slack []SlackIntegration `json:"slack,omitempty"`
|
||||
Sns []SnsIntegration `json:"sns,omitempty"`
|
||||
Teams []TeamsIntegration `json:"teams,omitempty"`
|
||||
Telegram []TelegramIntegration `json:"telegram,omitempty"`
|
||||
Threema []ThreemaIntegration `json:"threema,omitempty"`
|
||||
Victorops []VictoropsIntegration `json:"victorops,omitempty"`
|
||||
Webhook []WebhookIntegration `json:"webhook,omitempty"`
|
||||
Wecom []WecomIntegration `json:"wecom,omitempty"`
|
||||
Webex []WebexIntegration `json:"webex,omitempty"`
|
||||
}
|
||||
|
||||
// NewV0alpha2SpecIntegrations creates a new V0alpha2SpecIntegrations object.
|
||||
func NewV0alpha2SpecIntegrations() *V0alpha2SpecIntegrations {
|
||||
return &V0alpha2SpecIntegrations{}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
// Code generated - EDITING IS FUTILE. DO NOT EDIT.
|
||||
|
||||
package v0alpha2
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type StatusOperatorState struct {
|
||||
// lastEvaluation is the ResourceVersion last evaluated
|
||||
LastEvaluation string `json:"lastEvaluation"`
|
||||
// state describes the state of the lastEvaluation.
|
||||
// It is limited to three possible states for machine evaluation.
|
||||
State StatusOperatorStateState `json:"state"`
|
||||
// descriptiveState is an optional more descriptive state field which has no requirements on format
|
||||
DescriptiveState *string `json:"descriptiveState,omitempty"`
|
||||
// details contains any extra information that is operator-specific
|
||||
Details map[string]interface{} `json:"details,omitempty"`
|
||||
}
|
||||
|
||||
// NewStatusOperatorState creates a new StatusOperatorState object.
|
||||
func NewStatusOperatorState() *StatusOperatorState {
|
||||
return &StatusOperatorState{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type Status struct {
|
||||
// operatorStates is a map of operator ID to operator state evaluations.
|
||||
// Any operator which consumes this kind SHOULD add its state evaluation information to this field.
|
||||
OperatorStates map[string]StatusOperatorState `json:"operatorStates,omitempty"`
|
||||
// additionalFields is reserved for future use
|
||||
AdditionalFields map[string]interface{} `json:"additionalFields,omitempty"`
|
||||
}
|
||||
|
||||
// NewStatus creates a new Status object.
|
||||
func NewStatus() *Status {
|
||||
return &Status{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type StatusOperatorStateState string
|
||||
|
||||
const (
|
||||
StatusOperatorStateStateSuccess StatusOperatorStateState = "success"
|
||||
StatusOperatorStateStateInProgress StatusOperatorStateState = "in_progress"
|
||||
StatusOperatorStateStateFailed StatusOperatorStateState = "failed"
|
||||
)
|
||||
File diff suppressed because it is too large
Load Diff
+86
@@ -0,0 +1,86 @@
|
||||
API rule violation: list_type_missing,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,EmailIntegration,Addresses
|
||||
API rule violation: list_type_missing,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,JiraIntegration,Labels
|
||||
API rule violation: list_type_missing,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,OpsgenieIntegration,Responders
|
||||
API rule violation: list_type_missing,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,V0alpha2SpecIntegrations,Alertmanager
|
||||
API rule violation: list_type_missing,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,V0alpha2SpecIntegrations,Dingding
|
||||
API rule violation: list_type_missing,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,V0alpha2SpecIntegrations,Discord
|
||||
API rule violation: list_type_missing,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,V0alpha2SpecIntegrations,Email
|
||||
API rule violation: list_type_missing,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,V0alpha2SpecIntegrations,Googlechat
|
||||
API rule violation: list_type_missing,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,V0alpha2SpecIntegrations,Jira
|
||||
API rule violation: list_type_missing,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,V0alpha2SpecIntegrations,Kafka
|
||||
API rule violation: list_type_missing,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,V0alpha2SpecIntegrations,Line
|
||||
API rule violation: list_type_missing,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,V0alpha2SpecIntegrations,Mqtt
|
||||
API rule violation: list_type_missing,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,V0alpha2SpecIntegrations,Oncall
|
||||
API rule violation: list_type_missing,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,V0alpha2SpecIntegrations,Opsgenie
|
||||
API rule violation: list_type_missing,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,V0alpha2SpecIntegrations,Pagerduty
|
||||
API rule violation: list_type_missing,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,V0alpha2SpecIntegrations,Pushover
|
||||
API rule violation: list_type_missing,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,V0alpha2SpecIntegrations,Sensugo
|
||||
API rule violation: list_type_missing,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,V0alpha2SpecIntegrations,Slack
|
||||
API rule violation: list_type_missing,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,V0alpha2SpecIntegrations,Sns
|
||||
API rule violation: list_type_missing,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,V0alpha2SpecIntegrations,Teams
|
||||
API rule violation: list_type_missing,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,V0alpha2SpecIntegrations,Telegram
|
||||
API rule violation: list_type_missing,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,V0alpha2SpecIntegrations,Threema
|
||||
API rule violation: list_type_missing,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,V0alpha2SpecIntegrations,Victorops
|
||||
API rule violation: list_type_missing,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,V0alpha2SpecIntegrations,Webex
|
||||
API rule violation: list_type_missing,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,V0alpha2SpecIntegrations,Webhook
|
||||
API rule violation: list_type_missing,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,V0alpha2SpecIntegrations,Wecom
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,AlertmanagerIntegration,DisableResolveMessage
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,DingdingIntegration,DisableResolveMessage
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,DiscordIntegration,AvatarUrl
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,DiscordIntegration,DisableResolveMessage
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,DiscordIntegration,UseDiscordUsername
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,EmailIntegration,DisableResolveMessage
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,GooglechatIntegration,DisableResolveMessage
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,JiraIntegration,ApiToken
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,JiraIntegration,ApiUrl
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,JiraIntegration,DedupKeyField
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,JiraIntegration,DisableResolveMessage
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,JiraIntegration,IssueType
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,JiraIntegration,ReopenDuration
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,JiraIntegration,ReopenTransition
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,JiraIntegration,ResolveTransition
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,JiraIntegration,WontFixResolution
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,KafkaIntegration,DisableResolveMessage
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,LineIntegration,DisableResolveMessage
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,MqttIntegration,DisableResolveMessage
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,OnCallIntegration,AuthorizationCredentials
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,OnCallIntegration,AuthorizationScheme
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,OnCallIntegration,DisableResolveMessage
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,OpsgenieIntegration,DisableResolveMessage
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,PagerdutyIntegration,ClientUrl
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,PagerdutyIntegration,DisableResolveMessage
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,PushoverIntegration,DisableResolveMessage
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,SensugoIntegration,DisableResolveMessage
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,SigV4Config,AccessKey
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,SigV4Config,RoleArn
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,SigV4Config,SecretKey
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,SlackIntegration,DisableResolveMessage
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,SlackIntegration,IconEmoji
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,SlackIntegration,IconUrl
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,SnsIntegration,ApiUrl
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,SnsIntegration,DisableResolveMessage
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,SnsIntegration,PhoneNumber
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,SnsIntegration,TargetArn
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,SnsIntegration,TopicArn
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,TeamsIntegration,DisableResolveMessage
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,TelegramIntegration,DisableNotifications
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,TelegramIntegration,DisableResolveMessage
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,TelegramIntegration,DisableWebPagePreview
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,TelegramIntegration,MessageThreadId
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,TelegramIntegration,ParseMode
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,TelegramIntegration,ProtectContent
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,ThreemaIntegration,ApiSecret
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,ThreemaIntegration,DisableResolveMessage
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,ThreemaIntegration,GatewayId
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,ThreemaIntegration,RecipientId
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,VictoropsIntegration,DisableResolveMessage
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,WebexIntegration,ApiUrl
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,WebexIntegration,BotToken
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,WebexIntegration,DisableResolveMessage
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,WebexIntegration,RoomId
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,WebhookIntegration,AuthorizationCredentials
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,WebhookIntegration,AuthorizationScheme
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,WebhookIntegration,DisableResolveMessage
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,WecomIntegration,AgentId
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,WecomIntegration,CorpId
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2,WecomIntegration,DisableResolveMessage
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
|
||||
"github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/alerting/v0alpha1"
|
||||
receiverv0alpha1 "github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha1"
|
||||
receiverv0alpha2 "github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2"
|
||||
routingtreev0alpha1 "github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/routingtree/v0alpha1"
|
||||
templategroupv0alpha1 "github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/templategroup/v0alpha1"
|
||||
timeintervalv0alpha1 "github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/timeinterval/v0alpha1"
|
||||
@@ -17,12 +18,14 @@ import (
|
||||
func GetOpenAPIDefinitions(c common.ReferenceCallback) map[string]common.OpenAPIDefinition {
|
||||
tmpl := templategroupv0alpha1.GetOpenAPIDefinitions(c)
|
||||
tin := timeintervalv0alpha1.GetOpenAPIDefinitions(c)
|
||||
recv := receiverv0alpha1.GetOpenAPIDefinitions(c)
|
||||
recv1 := receiverv0alpha1.GetOpenAPIDefinitions(c)
|
||||
recv2 := receiverv0alpha2.GetOpenAPIDefinitions(c)
|
||||
rest := routingtreev0alpha1.GetOpenAPIDefinitions(c)
|
||||
result := make(map[string]common.OpenAPIDefinition, len(tmpl)+len(tin)+len(recv)+len(rest))
|
||||
result := make(map[string]common.OpenAPIDefinition, len(tmpl)+len(tin)+len(recv1)+len(rest)+len(recv2))
|
||||
maps.Copy(result, tmpl)
|
||||
maps.Copy(result, tin)
|
||||
maps.Copy(result, recv)
|
||||
maps.Copy(result, recv1)
|
||||
maps.Copy(result, recv2)
|
||||
maps.Copy(result, rest)
|
||||
return result
|
||||
}
|
||||
@@ -35,6 +38,9 @@ func GetKinds() map[schema.GroupVersion][]sdkResource.Kind {
|
||||
templategroupv0alpha1.Kind(),
|
||||
timeintervalv0alpha1.Kind(),
|
||||
},
|
||||
receiverv0alpha2.GroupVersion: {
|
||||
receiverv0alpha2.Kind(),
|
||||
},
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -11,6 +11,8 @@ import (
|
||||
"github.com/grafana/grafana-app-sdk/app"
|
||||
)
|
||||
|
||||
var ()
|
||||
|
||||
var appManifestData = app.ManifestData{
|
||||
AppName: "folder",
|
||||
Group: "folder.grafana.app",
|
||||
|
||||
@@ -9,7 +9,7 @@ import { resolve } from 'node:path';
|
||||
|
||||
// these snapshots are generated by running "go test pkg/tests/apis/openapi_test.go", see the README in the "openapi_snapshots" directory
|
||||
const OPENAPI_SCHEMA_LOCATION = resolve(
|
||||
'../../../pkg/tests/apis/openapi_snapshots/notifications.alerting.grafana.app-v0alpha1.json'
|
||||
'../../../pkg/tests/apis/openapi_snapshots/notifications.alerting.grafana.app-v0alpha2.json'
|
||||
);
|
||||
|
||||
export default {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,19 +1,9 @@
|
||||
import { fetchBaseQuery, TypedUseQueryHookResult } from '@reduxjs/toolkit/query/react';
|
||||
|
||||
import { config } from '@grafana/runtime';
|
||||
|
||||
import { alertingAPI, ListReceiverApiArg } from '../../api.gen';
|
||||
import { EnhancedListReceiverResponse } from '../types';
|
||||
import { alertingAPI } from '../../api.gen';
|
||||
|
||||
const { namespace } = config;
|
||||
|
||||
// this is a workaround for the fact that the generated types are not narrow enough
|
||||
type EnhancedHookResult = TypedUseQueryHookResult<
|
||||
EnhancedListReceiverResponse,
|
||||
ListReceiverApiArg,
|
||||
ReturnType<typeof fetchBaseQuery>
|
||||
>;
|
||||
|
||||
/**
|
||||
* useListContactPoints is a hook that fetches a list of contact points
|
||||
*
|
||||
@@ -23,7 +13,7 @@ type EnhancedHookResult = TypedUseQueryHookResult<
|
||||
* It automatically uses the configured namespace for the query.
|
||||
*/
|
||||
function useListContactPoints() {
|
||||
return alertingAPI.useListReceiverQuery<EnhancedHookResult>({ namespace });
|
||||
return alertingAPI.useListReceiverQuery({ namespace });
|
||||
}
|
||||
|
||||
export { useListContactPoints };
|
||||
|
||||
@@ -1,76 +1,6 @@
|
||||
/**
|
||||
* This file contains enhanced and type-narrowed versions of the types generated by the RTKQ codegen package.
|
||||
*/
|
||||
import { MergeDeep, MergeExclusive, OverrideProperties } from 'type-fest';
|
||||
import { ComGithubGrafanaGrafanaAppsAlertingNotificationsPkgApisReceiverV0Alpha2Receiver } from '../api.gen';
|
||||
|
||||
import {
|
||||
ComGithubGrafanaGrafanaAppsAlertingNotificationsPkgApisReceiverV0Alpha1Receiver as ContactPointV0Alpha1,
|
||||
ComGithubGrafanaGrafanaAppsAlertingNotificationsPkgApisReceiverV0Alpha1Integration as IntegrationV0Alpha1,
|
||||
ListReceiverApiResponse,
|
||||
} from '../api.gen';
|
||||
|
||||
type GenericIntegration = OverrideProperties<
|
||||
IntegrationV0Alpha1,
|
||||
{
|
||||
settings: Record<string, unknown>;
|
||||
}
|
||||
>;
|
||||
|
||||
// Based on https://github.com/grafana/alerting/blob/main/receivers/email/config.go#L20-L25
|
||||
type EmailIntegration = OverrideProperties<
|
||||
GenericIntegration,
|
||||
{
|
||||
type: 'email';
|
||||
settings: {
|
||||
singleEmail?: boolean;
|
||||
addresses: string;
|
||||
message?: string;
|
||||
subject?: string;
|
||||
};
|
||||
secureFields: never; // email doesn't have any secure fields
|
||||
}
|
||||
>;
|
||||
|
||||
// Based on https://github.com/grafana/alerting/blob/main/receivers/slack/config.go
|
||||
type SlackIntegration = OverrideProperties<
|
||||
GenericIntegration,
|
||||
{
|
||||
type: 'slack';
|
||||
settings: {
|
||||
endpointUrl?: string;
|
||||
url?: string;
|
||||
recipient?: string;
|
||||
text?: string;
|
||||
title?: string;
|
||||
username?: string;
|
||||
icon_emoji?: string;
|
||||
icon_url?: string;
|
||||
mentionChannel?: string;
|
||||
mentionUsers?: string; // comma separated string
|
||||
mentionGroups?: string; // comma separated string
|
||||
color?: string;
|
||||
};
|
||||
// secureFields is a union type that can be either a token or a URL but you can't have both
|
||||
secureFields: MergeExclusive<{ token: string }, { url: string }>;
|
||||
}
|
||||
>;
|
||||
|
||||
export type Integration = EmailIntegration | SlackIntegration | GenericIntegration;
|
||||
|
||||
// Enhanced version of ContactPoint with typed integrations
|
||||
// ⚠️ MergeDeep does not check if the property you are overriding exists in the base type and there is no "DeepOverrideProperties" helper
|
||||
export type ContactPoint = MergeDeep<
|
||||
ContactPointV0Alpha1,
|
||||
{
|
||||
spec: {
|
||||
integrations: Integration[];
|
||||
};
|
||||
}
|
||||
>;
|
||||
|
||||
export type EnhancedListReceiverResponse = OverrideProperties<
|
||||
ListReceiverApiResponse,
|
||||
{
|
||||
items: ContactPoint[];
|
||||
}
|
||||
>;
|
||||
export type ContactPoint = ComGithubGrafanaGrafanaAppsAlertingNotificationsPkgApisReceiverV0Alpha2Receiver;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { countBy, isEmpty } from 'lodash';
|
||||
import { isEmpty, mapValues } from 'lodash';
|
||||
|
||||
import { ContactPoint } from './types';
|
||||
|
||||
@@ -13,12 +13,15 @@ import { ContactPoint } from './types';
|
||||
* @returns A string description of the ContactPoint's integrations
|
||||
*/
|
||||
export function getContactPointDescription(contactPoint: ContactPoint): string {
|
||||
if (isEmpty(contactPoint.spec.integrations)) {
|
||||
const integrations = contactPoint.spec.integrations;
|
||||
|
||||
const isEmptyContactPoint = Object.values(integrations).every(isEmpty);
|
||||
if (isEmptyContactPoint) {
|
||||
return '<empty contact point>';
|
||||
}
|
||||
|
||||
// Count the occurrences of each integration type
|
||||
const integrationCounts = countBy(contactPoint.spec.integrations, (integration) => integration.type);
|
||||
const integrationCounts = mapValues(integrations, (integrations) => integrations?.length ?? 0);
|
||||
|
||||
const description = Object.entries(integrationCounts)
|
||||
.map(([type, count]) => {
|
||||
|
||||
@@ -9,6 +9,8 @@ import (
|
||||
|
||||
"github.com/grafana/grafana/pkg/apimachinery/errutil"
|
||||
"github.com/grafana/grafana/pkg/apimachinery/identity"
|
||||
"github.com/grafana/grafana/pkg/registry/apps/alerting/notifications/receiver/v0alpha1"
|
||||
"github.com/grafana/grafana/pkg/registry/apps/alerting/notifications/receiver/v0alpha2"
|
||||
"github.com/grafana/grafana/pkg/services/ngalert/accesscontrol"
|
||||
)
|
||||
|
||||
@@ -22,7 +24,7 @@ type AccessControlService interface {
|
||||
}
|
||||
|
||||
func Authorize(ctx context.Context, ac AccessControlService, attr authorizer.Attributes) (authorized authorizer.Decision, reason string, err error) {
|
||||
if attr.GetResource() != ResourceInfo.GroupResource().Resource {
|
||||
if attr.GetResource() != v0alpha1.ResourceInfo.GroupResource().Resource && attr.GetResource() != v0alpha2.ResourceInfo.GroupResource().Resource {
|
||||
return authorizer.DecisionNoOpinion, "", nil
|
||||
}
|
||||
user, err := identity.GetRequester(ctx)
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package receiver
|
||||
package v0alpha1
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
+4
-4
@@ -1,4 +1,4 @@
|
||||
package receiver
|
||||
package v0alpha1
|
||||
|
||||
import (
|
||||
"context"
|
||||
@@ -76,9 +76,9 @@ func (s *legacyStorage) List(ctx context.Context, opts *internalversion.ListOpti
|
||||
q := ngmodels.GetReceiversQuery{
|
||||
OrgID: orgId,
|
||||
Decrypt: false,
|
||||
//Names: ctx.QueryStrings("names"), // TODO: Query params.
|
||||
//Limit: ctx.QueryInt("limit"),
|
||||
//Offset: ctx.QueryInt("offset"),
|
||||
// Names: ctx.QueryStrings("names"), // TODO: Query params.
|
||||
// Limit: ctx.QueryInt("limit"),
|
||||
// Offset: ctx.QueryInt("offset"),
|
||||
}
|
||||
|
||||
user, err := identity.GetRequester(ctx)
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package receiver
|
||||
package v0alpha1
|
||||
|
||||
import (
|
||||
grafanarest "github.com/grafana/grafana/pkg/apiserver/rest"
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package receiver
|
||||
package v0alpha1
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@@ -0,0 +1,615 @@
|
||||
package v0alpha2
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"unsafe"
|
||||
|
||||
"github.com/grafana/alerting/receivers"
|
||||
|
||||
jsoniter "github.com/json-iterator/go"
|
||||
"github.com/modern-go/reflect2"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/fields"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
|
||||
model "github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2"
|
||||
"github.com/grafana/grafana/pkg/services/apiserver/endpoints/request"
|
||||
gapiutil "github.com/grafana/grafana/pkg/services/apiserver/utils"
|
||||
ngmodels "github.com/grafana/grafana/pkg/services/ngalert/models"
|
||||
"github.com/grafana/grafana/pkg/util"
|
||||
)
|
||||
|
||||
func convertToK8sResources(
|
||||
orgID int64,
|
||||
receivers []*ngmodels.Receiver,
|
||||
accesses map[string]ngmodels.ReceiverPermissionSet,
|
||||
metadatas map[string]ngmodels.ReceiverMetadata,
|
||||
namespacer request.NamespaceMapper,
|
||||
selector fields.Selector,
|
||||
) (*model.ReceiverList, error) {
|
||||
result := &model.ReceiverList{
|
||||
Items: make([]model.Receiver, 0, len(receivers)),
|
||||
}
|
||||
for _, receiver := range receivers {
|
||||
var access *ngmodels.ReceiverPermissionSet
|
||||
if accesses != nil {
|
||||
if a, ok := accesses[receiver.GetUID()]; ok {
|
||||
access = &a
|
||||
}
|
||||
}
|
||||
var metadata *ngmodels.ReceiverMetadata
|
||||
if metadatas != nil {
|
||||
if m, ok := metadatas[receiver.GetUID()]; ok {
|
||||
metadata = &m
|
||||
}
|
||||
}
|
||||
k8sResource, err := convertToK8sResource(orgID, receiver, access, metadata, namespacer, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if selector != nil && !selector.Empty() && !selector.Matches(model.SelectableFields(k8sResource)) {
|
||||
continue
|
||||
}
|
||||
result.Items = append(result.Items, *k8sResource)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func convertToK8sResource(
|
||||
orgID int64,
|
||||
receiver *ngmodels.Receiver,
|
||||
access *ngmodels.ReceiverPermissionSet,
|
||||
metadata *ngmodels.ReceiverMetadata,
|
||||
namespacer request.NamespaceMapper,
|
||||
keepSecrets bool,
|
||||
) (*model.Receiver, error) {
|
||||
spec, err := specFromDomainReceiver(receiver, keepSecrets)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
r := &model.Receiver{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
UID: types.UID(receiver.GetUID()), // This is needed to make PATCH work
|
||||
Name: receiver.GetUID(),
|
||||
Namespace: namespacer(orgID),
|
||||
ResourceVersion: receiver.Version,
|
||||
},
|
||||
Spec: spec,
|
||||
}
|
||||
r.SetProvenanceStatus(string(receiver.Provenance))
|
||||
|
||||
if access != nil {
|
||||
for _, action := range ngmodels.ReceiverPermissions() {
|
||||
mappedAction, ok := permissionMapper[action]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("unknown action %v", action)
|
||||
}
|
||||
if can, _ := access.Has(action); can {
|
||||
r.SetAccessControl(mappedAction)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if metadata != nil {
|
||||
rules := make([]string, 0, len(metadata.InUseByRules))
|
||||
for _, rule := range metadata.InUseByRules {
|
||||
rules = append(rules, rule.UID)
|
||||
}
|
||||
r.SetInUse(metadata.InUseByRoutes, rules)
|
||||
}
|
||||
r.UID = gapiutil.CalculateClusterWideUID(r)
|
||||
return r, nil
|
||||
}
|
||||
|
||||
var permissionMapper = map[ngmodels.ReceiverPermission]string{
|
||||
ngmodels.ReceiverPermissionReadSecret: "canReadSecrets",
|
||||
ngmodels.ReceiverPermissionAdmin: "canAdmin",
|
||||
ngmodels.ReceiverPermissionWrite: "canWrite",
|
||||
ngmodels.ReceiverPermissionDelete: "canDelete",
|
||||
}
|
||||
|
||||
// ContactPointFromContactPointExport parses the database model of the contact point (group of integrations) where settings are represented in JSON,
|
||||
// to strongly typed ContactPoint.
|
||||
func specFromDomainReceiver(domain *ngmodels.Receiver, secrets bool) (model.Spec, error) {
|
||||
j := jsoniter.ConfigCompatibleWithStandardLibrary
|
||||
j.RegisterExtension(&contactPointsExtension{
|
||||
KeepSecret: secrets,
|
||||
})
|
||||
|
||||
result := model.Spec{
|
||||
Title: domain.Name,
|
||||
}
|
||||
|
||||
var errs []error
|
||||
for _, rawIntegration := range domain.Integrations {
|
||||
err := parseIntegration(j, &result, rawIntegration)
|
||||
if err != nil {
|
||||
// accumulate errors to report all at once.
|
||||
errs = append(errs, fmt.Errorf("failed to parse %s integration (uid:%s): %w", rawIntegration.Config.Type, rawIntegration.UID, err))
|
||||
}
|
||||
}
|
||||
return result, errors.Join(errs...)
|
||||
}
|
||||
|
||||
// ContactPointToContactPointExport converts v0alpha2.Receiver to models.Receiver.
|
||||
// It uses a special extension for json-iterator API that properly handles marshaling of some specific fields.
|
||||
//
|
||||
//nolint:gocyclo
|
||||
func convertToDomainModel(apiModel *model.Receiver) (*ngmodels.Receiver, error) {
|
||||
j := jsoniter.ConfigCompatibleWithStandardLibrary
|
||||
// use json iterator with custom extension that has special codec for some field.
|
||||
// This is needed to keep the API models clean and convert from a database model
|
||||
j.RegisterExtension(&contactPointsExtension{})
|
||||
|
||||
cp := apiModel.Spec
|
||||
|
||||
integration := make([]*ngmodels.Integration, 0, apiModel.Spec.IntegrationsCount())
|
||||
|
||||
var errs []error
|
||||
for _, i := range cp.Integrations.Alertmanager {
|
||||
el, err := marshallIntegration(j, "prometheus-alertmanager", i, i.DisableResolveMessage, i.Uid, cp.Title)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
integration = append(integration, el)
|
||||
}
|
||||
for _, i := range cp.Integrations.Dingding {
|
||||
el, err := marshallIntegration(j, "dingding", i, i.DisableResolveMessage, i.Uid, cp.Title)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
integration = append(integration, el)
|
||||
}
|
||||
for _, i := range cp.Integrations.Discord {
|
||||
el, err := marshallIntegration(j, "discord", i, i.DisableResolveMessage, i.Uid, cp.Title)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
integration = append(integration, el)
|
||||
}
|
||||
for _, i := range cp.Integrations.Email {
|
||||
el, err := marshallIntegration(j, "email", i, i.DisableResolveMessage, i.Uid, cp.Title)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
integration = append(integration, el)
|
||||
}
|
||||
for _, i := range cp.Integrations.Googlechat {
|
||||
el, err := marshallIntegration(j, "googlechat", i, i.DisableResolveMessage, i.Uid, cp.Title)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
integration = append(integration, el)
|
||||
}
|
||||
for _, i := range cp.Integrations.Jira {
|
||||
el, err := marshallIntegration(j, "jira", i, i.DisableResolveMessage, i.Uid, cp.Title)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
integration = append(integration, el)
|
||||
}
|
||||
for _, i := range cp.Integrations.Kafka {
|
||||
el, err := marshallIntegration(j, "kafka", i, i.DisableResolveMessage, i.Uid, cp.Title)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
integration = append(integration, el)
|
||||
}
|
||||
for _, i := range cp.Integrations.Line {
|
||||
el, err := marshallIntegration(j, "line", i, i.DisableResolveMessage, i.Uid, cp.Title)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
integration = append(integration, el)
|
||||
}
|
||||
for _, i := range cp.Integrations.Mqtt {
|
||||
el, err := marshallIntegration(j, "mqtt", i, i.DisableResolveMessage, i.Uid, cp.Title)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
integration = append(integration, el)
|
||||
}
|
||||
for _, i := range cp.Integrations.Opsgenie {
|
||||
el, err := marshallIntegration(j, "opsgenie", i, i.DisableResolveMessage, i.Uid, cp.Title)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
integration = append(integration, el)
|
||||
}
|
||||
for _, i := range cp.Integrations.Pagerduty {
|
||||
el, err := marshallIntegration(j, "pagerduty", i, i.DisableResolveMessage, i.Uid, cp.Title)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
integration = append(integration, el)
|
||||
}
|
||||
for _, i := range cp.Integrations.Oncall {
|
||||
el, err := marshallIntegration(j, "oncall", i, i.DisableResolveMessage, i.Uid, cp.Title)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
integration = append(integration, el)
|
||||
}
|
||||
for _, i := range cp.Integrations.Pushover {
|
||||
el, err := marshallIntegration(j, "pushover", i, i.DisableResolveMessage, i.Uid, cp.Title)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
integration = append(integration, el)
|
||||
}
|
||||
for _, i := range cp.Integrations.Sensugo {
|
||||
el, err := marshallIntegration(j, "sensugo", i, i.DisableResolveMessage, i.Uid, cp.Title)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
integration = append(integration, el)
|
||||
}
|
||||
for _, i := range cp.Integrations.Sns {
|
||||
el, err := marshallIntegration(j, "sns", i, i.DisableResolveMessage, i.Uid, cp.Title)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
integration = append(integration, el)
|
||||
}
|
||||
for _, i := range cp.Integrations.Slack {
|
||||
el, err := marshallIntegration(j, "slack", i, i.DisableResolveMessage, i.Uid, cp.Title)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
integration = append(integration, el)
|
||||
}
|
||||
for _, i := range cp.Integrations.Teams {
|
||||
el, err := marshallIntegration(j, "teams", i, i.DisableResolveMessage, i.Uid, cp.Title)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
integration = append(integration, el)
|
||||
}
|
||||
for _, i := range cp.Integrations.Telegram {
|
||||
el, err := marshallIntegration(j, "telegram", i, i.DisableResolveMessage, i.Uid, cp.Title)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
integration = append(integration, el)
|
||||
}
|
||||
for _, i := range cp.Integrations.Threema {
|
||||
el, err := marshallIntegration(j, "threema", i, i.DisableResolveMessage, i.Uid, cp.Title)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
integration = append(integration, el)
|
||||
}
|
||||
for _, i := range cp.Integrations.Victorops {
|
||||
el, err := marshallIntegration(j, "victorops", i, i.DisableResolveMessage, i.Uid, cp.Title)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
integration = append(integration, el)
|
||||
}
|
||||
for _, i := range cp.Integrations.Webhook {
|
||||
el, err := marshallIntegration(j, "webhook", i, i.DisableResolveMessage, i.Uid, cp.Title)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
integration = append(integration, el)
|
||||
}
|
||||
for _, i := range cp.Integrations.Wecom {
|
||||
el, err := marshallIntegration(j, "wecom", i, i.DisableResolveMessage, i.Uid, cp.Title)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
integration = append(integration, el)
|
||||
}
|
||||
for _, i := range cp.Integrations.Webex {
|
||||
el, err := marshallIntegration(j, "webex", i, i.DisableResolveMessage, i.Uid, cp.Title)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
integration = append(integration, el)
|
||||
}
|
||||
|
||||
if len(errs) > 0 {
|
||||
return nil, errors.Join(errs...)
|
||||
}
|
||||
result := &ngmodels.Receiver{
|
||||
UID: apiModel.Name,
|
||||
Name: apiModel.Spec.Title,
|
||||
Integrations: integration,
|
||||
Provenance: ngmodels.Provenance(apiModel.GetProvenanceStatus()),
|
||||
Version: apiModel.ResourceVersion,
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// marshallIntegration converts the API model integration to the storage model that contains settings in the JSON format.
|
||||
// The secret fields are not encrypted.
|
||||
func marshallIntegration(json jsoniter.API, integrationType string, integration interface{}, disableResolveMessage *bool, uid *string, name string) (*ngmodels.Integration, error) {
|
||||
data, err := json.Marshal(integration)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to marshall integration '%s' to JSON: %w", integrationType, err)
|
||||
}
|
||||
settings := map[string]interface{}{}
|
||||
err = json.Unmarshal(data, &settings)
|
||||
delete(settings, "uid") // integration UID is part of the integration
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to marshall integration '%s' to map: %w", integrationType, err)
|
||||
}
|
||||
|
||||
config, err := ngmodels.IntegrationConfigFromType(integrationType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
e := &ngmodels.Integration{
|
||||
UID: "",
|
||||
Name: name,
|
||||
Config: config,
|
||||
Settings: settings,
|
||||
SecureSettings: nil,
|
||||
}
|
||||
if uid != nil {
|
||||
e.UID = *uid
|
||||
}
|
||||
if disableResolveMessage != nil {
|
||||
e.DisableResolveMessage = *disableResolveMessage
|
||||
}
|
||||
return e, nil
|
||||
}
|
||||
|
||||
//nolint:gocyclo
|
||||
func parseIntegration(json jsoniter.API, result *model.Spec, integration *ngmodels.Integration) error {
|
||||
var err error
|
||||
var disable *bool
|
||||
if integration.DisableResolveMessage { // populate only if true
|
||||
disable = util.Pointer(integration.DisableResolveMessage)
|
||||
}
|
||||
|
||||
data, err := json.Marshal(integration.Settings)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to marshall integration '%s' to JSON: %w", integration.Config.Type, err)
|
||||
}
|
||||
switch strings.ToLower(integration.Config.Type) {
|
||||
case "prometheus-alertmanager":
|
||||
integration := model.AlertmanagerIntegration{DisableResolveMessage: disable, Uid: util.Pointer(integration.UID)}
|
||||
if err = json.Unmarshal(data, &integration); err == nil {
|
||||
result.Integrations.Alertmanager = append(result.Integrations.Alertmanager, integration)
|
||||
}
|
||||
case "dingding":
|
||||
integration := model.DingdingIntegration{DisableResolveMessage: disable, Uid: util.Pointer(integration.UID)}
|
||||
if err = json.Unmarshal(data, &integration); err == nil {
|
||||
result.Integrations.Dingding = append(result.Integrations.Dingding, integration)
|
||||
}
|
||||
case "discord":
|
||||
integration := model.DiscordIntegration{DisableResolveMessage: disable, Uid: util.Pointer(integration.UID)}
|
||||
if err = json.Unmarshal(data, &integration); err == nil {
|
||||
result.Integrations.Discord = append(result.Integrations.Discord, integration)
|
||||
}
|
||||
case "email":
|
||||
integration := model.EmailIntegration{DisableResolveMessage: disable, Uid: util.Pointer(integration.UID)}
|
||||
if err = json.Unmarshal(data, &integration); err == nil {
|
||||
result.Integrations.Email = append(result.Integrations.Email, integration)
|
||||
}
|
||||
case "googlechat":
|
||||
integration := model.GooglechatIntegration{DisableResolveMessage: disable, Uid: util.Pointer(integration.UID)}
|
||||
if err = json.Unmarshal(data, &integration); err == nil {
|
||||
result.Integrations.Googlechat = append(result.Integrations.Googlechat, integration)
|
||||
}
|
||||
case "jira":
|
||||
integration := model.JiraIntegration{DisableResolveMessage: disable, Uid: util.Pointer(integration.UID)}
|
||||
if err = json.Unmarshal(data, &integration); err == nil {
|
||||
result.Integrations.Jira = append(result.Integrations.Jira, integration)
|
||||
}
|
||||
case "kafka":
|
||||
integration := model.KafkaIntegration{DisableResolveMessage: disable, Uid: util.Pointer(integration.UID)}
|
||||
if err = json.Unmarshal(data, &integration); err == nil {
|
||||
result.Integrations.Kafka = append(result.Integrations.Kafka, integration)
|
||||
}
|
||||
case "line":
|
||||
integration := model.LineIntegration{DisableResolveMessage: disable, Uid: util.Pointer(integration.UID)}
|
||||
if err = json.Unmarshal(data, &integration); err == nil {
|
||||
result.Integrations.Line = append(result.Integrations.Line, integration)
|
||||
}
|
||||
case "mqtt":
|
||||
integration := model.MqttIntegration{DisableResolveMessage: disable, Uid: util.Pointer(integration.UID)}
|
||||
if err = json.Unmarshal(data, &integration); err == nil {
|
||||
result.Integrations.Mqtt = append(result.Integrations.Mqtt, integration)
|
||||
}
|
||||
case "opsgenie":
|
||||
integration := model.OpsgenieIntegration{DisableResolveMessage: disable, Uid: util.Pointer(integration.UID)}
|
||||
if err = json.Unmarshal(data, &integration); err == nil {
|
||||
result.Integrations.Opsgenie = append(result.Integrations.Opsgenie, integration)
|
||||
}
|
||||
case "pagerduty":
|
||||
integration := model.PagerdutyIntegration{DisableResolveMessage: disable, Uid: util.Pointer(integration.UID)}
|
||||
if err = json.Unmarshal(data, &integration); err == nil {
|
||||
result.Integrations.Pagerduty = append(result.Integrations.Pagerduty, integration)
|
||||
}
|
||||
case "oncall":
|
||||
integration := model.OnCallIntegration{DisableResolveMessage: disable, Uid: util.Pointer(integration.UID)}
|
||||
if err = json.Unmarshal(data, &integration); err == nil {
|
||||
result.Integrations.Oncall = append(result.Integrations.Oncall, integration)
|
||||
}
|
||||
case "pushover":
|
||||
integration := model.PushoverIntegration{DisableResolveMessage: disable, Uid: util.Pointer(integration.UID)}
|
||||
if err = json.Unmarshal(data, &integration); err == nil {
|
||||
result.Integrations.Pushover = append(result.Integrations.Pushover, integration)
|
||||
}
|
||||
case "sensugo":
|
||||
integration := model.SensugoIntegration{DisableResolveMessage: disable, Uid: util.Pointer(integration.UID)}
|
||||
if err = json.Unmarshal(data, &integration); err == nil {
|
||||
result.Integrations.Sensugo = append(result.Integrations.Sensugo, integration)
|
||||
}
|
||||
case "sns":
|
||||
integration := model.SnsIntegration{DisableResolveMessage: disable, Uid: util.Pointer(integration.UID)}
|
||||
if err = json.Unmarshal(data, &integration); err == nil {
|
||||
result.Integrations.Sns = append(result.Integrations.Sns, integration)
|
||||
}
|
||||
case "slack":
|
||||
integration := model.SlackIntegration{DisableResolveMessage: disable, Uid: util.Pointer(integration.UID)}
|
||||
if err = json.Unmarshal(data, &integration); err == nil {
|
||||
result.Integrations.Slack = append(result.Integrations.Slack, integration)
|
||||
}
|
||||
case "teams":
|
||||
integration := model.TeamsIntegration{DisableResolveMessage: disable, Uid: util.Pointer(integration.UID)}
|
||||
if err = json.Unmarshal(data, &integration); err == nil {
|
||||
result.Integrations.Teams = append(result.Integrations.Teams, integration)
|
||||
}
|
||||
case "telegram":
|
||||
integration := model.TelegramIntegration{DisableResolveMessage: disable, Uid: util.Pointer(integration.UID)}
|
||||
if err = json.Unmarshal(data, &integration); err == nil {
|
||||
result.Integrations.Telegram = append(result.Integrations.Telegram, integration)
|
||||
}
|
||||
case "threema":
|
||||
integration := model.ThreemaIntegration{DisableResolveMessage: disable, Uid: util.Pointer(integration.UID)}
|
||||
if err = json.Unmarshal(data, &integration); err == nil {
|
||||
result.Integrations.Threema = append(result.Integrations.Threema, integration)
|
||||
}
|
||||
case "victorops":
|
||||
integration := model.VictoropsIntegration{DisableResolveMessage: disable, Uid: util.Pointer(integration.UID)}
|
||||
if err = json.Unmarshal(data, &integration); err == nil {
|
||||
result.Integrations.Victorops = append(result.Integrations.Victorops, integration)
|
||||
}
|
||||
case "webhook":
|
||||
integration := model.WebhookIntegration{DisableResolveMessage: disable, Uid: util.Pointer(integration.UID)}
|
||||
if err = json.Unmarshal(data, &integration); err == nil {
|
||||
result.Integrations.Webhook = append(result.Integrations.Webhook, integration)
|
||||
}
|
||||
case "wecom":
|
||||
integration := model.WecomIntegration{DisableResolveMessage: disable, Uid: util.Pointer(integration.UID)}
|
||||
if err = json.Unmarshal(data, &integration); err == nil {
|
||||
result.Integrations.Wecom = append(result.Integrations.Wecom, integration)
|
||||
}
|
||||
case "webex":
|
||||
integration := model.WebexIntegration{DisableResolveMessage: disable, Uid: util.Pointer(integration.UID)}
|
||||
if err = json.Unmarshal(data, &integration); err == nil {
|
||||
result.Integrations.Webex = append(result.Integrations.Webex, integration)
|
||||
}
|
||||
default:
|
||||
err = fmt.Errorf("integration %s is not supported", integration.Config.Type)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// contactPointsExtension extends jsoniter with special codecs for some integrations' fields that are encoded differently in the legacy configuration.
|
||||
type contactPointsExtension struct {
|
||||
jsoniter.DummyExtension
|
||||
KeepSecret bool
|
||||
}
|
||||
|
||||
func (c *contactPointsExtension) UpdateStructDescriptor(structDescriptor *jsoniter.StructDescriptor) {
|
||||
if structDescriptor.Type == reflect2.TypeOf(model.EmailIntegration{}) {
|
||||
bind := structDescriptor.GetField("Addresses")
|
||||
codec := &emailAddressCodec{}
|
||||
bind.Decoder = codec
|
||||
bind.Encoder = codec
|
||||
}
|
||||
if structDescriptor.Type == reflect2.TypeOf(model.PushoverIntegration{}) {
|
||||
codec := &numberAsStringCodec{}
|
||||
for _, field := range []string{"Priority", "OkPriority"} {
|
||||
desc := structDescriptor.GetField(field)
|
||||
desc.Decoder = codec
|
||||
desc.Encoder = codec
|
||||
}
|
||||
// the same logic is in the pushover.NewConfig in alerting module
|
||||
codec = &numberAsStringCodec{ignoreError: true}
|
||||
for _, field := range []string{"Retry", "Expire"} {
|
||||
desc := structDescriptor.GetField(field)
|
||||
desc.Decoder = codec
|
||||
desc.Encoder = codec
|
||||
}
|
||||
}
|
||||
if structDescriptor.Type == reflect2.TypeOf(model.WebhookIntegration{}) {
|
||||
codec := &numberAsStringCodec{ignoreError: true}
|
||||
desc := structDescriptor.GetField("MaxAlerts")
|
||||
desc.Decoder = codec
|
||||
desc.Encoder = codec
|
||||
}
|
||||
if structDescriptor.Type == reflect2.TypeOf(model.OnCallIntegration{}) {
|
||||
codec := &numberAsStringCodec{ignoreError: true}
|
||||
desc := structDescriptor.GetField("MaxAlerts")
|
||||
desc.Decoder = codec
|
||||
desc.Encoder = codec
|
||||
}
|
||||
if structDescriptor.Type == reflect2.TypeOf(model.MqttIntegration{}) {
|
||||
codec := &numberAsStringCodec{ignoreError: true}
|
||||
desc := structDescriptor.GetField("Qos")
|
||||
desc.Decoder = codec
|
||||
desc.Encoder = codec
|
||||
}
|
||||
}
|
||||
|
||||
type emailAddressCodec struct{}
|
||||
|
||||
func (d *emailAddressCodec) IsEmpty(ptr unsafe.Pointer) bool {
|
||||
f := *(*[]string)(ptr)
|
||||
return len(f) == 0
|
||||
}
|
||||
|
||||
func (d *emailAddressCodec) Encode(ptr unsafe.Pointer, stream *jsoniter.Stream) {
|
||||
f := *(*[]string)(ptr)
|
||||
addresses := strings.Join(f, ";")
|
||||
stream.WriteString(addresses)
|
||||
}
|
||||
|
||||
func (d *emailAddressCodec) Decode(ptr unsafe.Pointer, iter *jsoniter.Iterator) {
|
||||
s := iter.ReadString()
|
||||
emails := strings.FieldsFunc(strings.Trim(s, "\""), func(r rune) bool {
|
||||
switch r {
|
||||
case ',', ';', '\n':
|
||||
return true
|
||||
}
|
||||
return false
|
||||
})
|
||||
*((*[]string)(ptr)) = emails
|
||||
}
|
||||
|
||||
// converts a string representation of a number to *int64
|
||||
type numberAsStringCodec struct {
|
||||
ignoreError bool // if true, then ignores the error and keeps value nil
|
||||
}
|
||||
|
||||
func (d *numberAsStringCodec) IsEmpty(ptr unsafe.Pointer) bool {
|
||||
return *((*(*int))(ptr)) == nil
|
||||
}
|
||||
|
||||
func (d *numberAsStringCodec) Encode(ptr unsafe.Pointer, stream *jsoniter.Stream) {
|
||||
val := *((*(*int))(ptr))
|
||||
if val == nil {
|
||||
stream.WriteNil()
|
||||
return
|
||||
}
|
||||
stream.WriteInt(*val)
|
||||
}
|
||||
|
||||
func (d *numberAsStringCodec) Decode(ptr unsafe.Pointer, iter *jsoniter.Iterator) {
|
||||
valueType := iter.WhatIsNext()
|
||||
var value int64
|
||||
switch valueType {
|
||||
case jsoniter.NumberValue:
|
||||
value = iter.ReadInt64()
|
||||
case jsoniter.StringValue:
|
||||
var num receivers.OptionalNumber
|
||||
err := num.UnmarshalJSON(iter.ReadStringAsSlice())
|
||||
if err != nil {
|
||||
iter.ReportError("numberAsStringCodec", fmt.Sprintf("failed to unmarshall string as OptionalNumber: %s", err.Error()))
|
||||
}
|
||||
if num.String() == "" {
|
||||
return
|
||||
}
|
||||
value, err = num.Int64()
|
||||
if err != nil {
|
||||
if !d.ignoreError {
|
||||
iter.ReportError("numberAsStringCodec", fmt.Sprintf("string does not represent an integer number: %s", err.Error()))
|
||||
}
|
||||
return
|
||||
}
|
||||
case jsoniter.NilValue:
|
||||
iter.ReadNil()
|
||||
return
|
||||
default:
|
||||
iter.ReportError("numberAsStringCodec", "not number or string")
|
||||
}
|
||||
*((*(*int64))(ptr)) = &value
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package v0alpha2
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/grafana/alerting/notify"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/grafana/grafana/pkg/services/apiserver/endpoints/request"
|
||||
"github.com/grafana/grafana/pkg/services/ngalert/models"
|
||||
)
|
||||
|
||||
func TestConvertToK8sResource(t *testing.T) {
|
||||
for integrationType, cfg := range notify.AllKnownConfigsForTesting {
|
||||
t.Run(integrationType, func(t *testing.T) {
|
||||
schema, err := models.IntegrationConfigFromType(integrationType)
|
||||
require.NoError(t, err)
|
||||
settingsMap := map[string]any{}
|
||||
require.NoError(t, json.Unmarshal([]byte(cfg.Config), &settingsMap))
|
||||
recCfg := &models.Receiver{
|
||||
UID: fmt.Sprintf("uid-%s", integrationType),
|
||||
Name: fmt.Sprintf("name-%s", integrationType),
|
||||
Integrations: []*models.Integration{
|
||||
{
|
||||
UID: fmt.Sprintf("intuid-%s", integrationType),
|
||||
Name: fmt.Sprintf("name-%s", integrationType),
|
||||
Config: schema,
|
||||
DisableResolveMessage: false,
|
||||
Settings: settingsMap,
|
||||
SecureSettings: nil,
|
||||
},
|
||||
},
|
||||
Provenance: "api",
|
||||
Version: "1234",
|
||||
}
|
||||
|
||||
result, err := convertToK8sResource(1, recCfg, &models.ReceiverPermissionSet{}, &models.ReceiverMetadata{}, request.GetNamespaceMapper(nil), true)
|
||||
require.NoError(t, err)
|
||||
|
||||
back, err := convertToDomainModel(result)
|
||||
require.NoError(t, err)
|
||||
|
||||
switch integrationType {
|
||||
case "webhook": // webhook has a different format for maxAlerts, in test config it's a string, in API model it's an int.
|
||||
val := back.Integrations[0].Settings["maxAlerts"].(float64)
|
||||
back.Integrations[0].Settings["maxAlerts"] = fmt.Sprintf("%d", int(val))
|
||||
case "mqtt": // same for qos
|
||||
val := back.Integrations[0].Settings["qos"].(float64)
|
||||
back.Integrations[0].Settings["qos"] = fmt.Sprintf("%d", int(val))
|
||||
}
|
||||
diff := cmp.Diff(recCfg, back)
|
||||
if len(diff) != 0 {
|
||||
require.Failf(t, "The re-marshalled configuration does not match the expected one", diff)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,285 @@
|
||||
package v0alpha2
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/internalversion"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apiserver/pkg/registry/rest"
|
||||
|
||||
model "github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2"
|
||||
"github.com/grafana/grafana/pkg/apimachinery/identity"
|
||||
grafanarest "github.com/grafana/grafana/pkg/apiserver/rest"
|
||||
"github.com/grafana/grafana/pkg/services/apiserver/endpoints/request"
|
||||
alertingac "github.com/grafana/grafana/pkg/services/ngalert/accesscontrol"
|
||||
"github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions"
|
||||
ngmodels "github.com/grafana/grafana/pkg/services/ngalert/models"
|
||||
"github.com/grafana/grafana/pkg/services/ngalert/notifier/legacy_storage"
|
||||
)
|
||||
|
||||
var (
|
||||
_ grafanarest.Storage = (*legacyStorage)(nil)
|
||||
)
|
||||
|
||||
type ReceiverService interface {
|
||||
GetReceiver(ctx context.Context, q ngmodels.GetReceiverQuery, user identity.Requester) (*ngmodels.Receiver, error)
|
||||
GetReceivers(ctx context.Context, q ngmodels.GetReceiversQuery, user identity.Requester) ([]*ngmodels.Receiver, error)
|
||||
CreateReceiver(ctx context.Context, r *ngmodels.Receiver, orgID int64, user identity.Requester) (*ngmodels.Receiver, error)
|
||||
UpdateReceiver(ctx context.Context, r *ngmodels.Receiver, storedSecureFields map[string][]string, orgID int64, user identity.Requester) (*ngmodels.Receiver, error)
|
||||
DeleteReceiver(ctx context.Context, name string, provenance definitions.Provenance, version string, orgID int64, user identity.Requester) error
|
||||
}
|
||||
|
||||
type MetadataService interface {
|
||||
AccessControlMetadata(ctx context.Context, user identity.Requester, receivers ...*ngmodels.Receiver) (map[string]ngmodels.ReceiverPermissionSet, error)
|
||||
InUseMetadata(ctx context.Context, orgID int64, receivers ...*ngmodels.Receiver) (map[string]ngmodels.ReceiverMetadata, error)
|
||||
}
|
||||
|
||||
type legacyStorage struct {
|
||||
service ReceiverService
|
||||
namespacer request.NamespaceMapper
|
||||
tableConverter rest.TableConvertor
|
||||
metadata MetadataService
|
||||
}
|
||||
|
||||
func (s *legacyStorage) New() runtime.Object {
|
||||
return ResourceInfo.NewFunc()
|
||||
}
|
||||
|
||||
func (s *legacyStorage) Destroy() {}
|
||||
|
||||
func (s *legacyStorage) NamespaceScoped() bool {
|
||||
return true // namespace == org
|
||||
}
|
||||
|
||||
func (s *legacyStorage) GetSingularName() string {
|
||||
return ResourceInfo.GetSingularName()
|
||||
}
|
||||
|
||||
func (s *legacyStorage) NewList() runtime.Object {
|
||||
return ResourceInfo.NewListFunc()
|
||||
}
|
||||
|
||||
func (s *legacyStorage) ConvertToTable(ctx context.Context, object runtime.Object, tableOptions runtime.Object) (*metav1.Table, error) {
|
||||
return s.tableConverter.ConvertToTable(ctx, object, tableOptions)
|
||||
}
|
||||
|
||||
func (s *legacyStorage) List(ctx context.Context, opts *internalversion.ListOptions) (runtime.Object, error) {
|
||||
orgId, err := request.OrgIDForList(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
q := ngmodels.GetReceiversQuery{
|
||||
OrgID: orgId,
|
||||
Decrypt: true,
|
||||
}
|
||||
|
||||
user, err := identity.GetRequester(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res, err := s.service.GetReceivers(ctx, q, user)
|
||||
if err != nil {
|
||||
// This API should not be returning a forbidden error when the user does not have access to any resources.
|
||||
// This can be true for a contact point creator role, for example.
|
||||
// This should eventually be changed downstream in the auth logic but provisioning API currently relies on this
|
||||
// behaviour to return useful forbidden errors when exporting decrypted receivers.
|
||||
if !errors.Is(err, alertingac.ErrAuthorizationBase) {
|
||||
return nil, err
|
||||
}
|
||||
res = nil
|
||||
}
|
||||
|
||||
accesses, err := s.metadata.AccessControlMetadata(ctx, user, res...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get access control metadata: %w", err)
|
||||
}
|
||||
|
||||
inUses, err := s.metadata.InUseMetadata(ctx, orgId, res...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get in-use metadata: %w", err)
|
||||
}
|
||||
|
||||
return convertToK8sResources(orgId, res, accesses, inUses, s.namespacer, opts.FieldSelector)
|
||||
}
|
||||
|
||||
func (s *legacyStorage) Get(ctx context.Context, uid string, _ *metav1.GetOptions) (runtime.Object, error) {
|
||||
return s.get(ctx, uid, false, true)
|
||||
}
|
||||
|
||||
func (s *legacyStorage) get(ctx context.Context, uid string, keepSecrets bool, fillMetadata bool) (runtime.Object, error) {
|
||||
info, err := request.NamespaceInfoFrom(ctx, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
name, err := legacy_storage.UidToName(uid)
|
||||
if err != nil {
|
||||
return nil, apierrors.NewNotFound(ResourceInfo.GroupResource(), uid)
|
||||
}
|
||||
q := ngmodels.GetReceiverQuery{
|
||||
OrgID: info.OrgID,
|
||||
Name: name,
|
||||
Decrypt: true,
|
||||
}
|
||||
|
||||
user, err := identity.GetRequester(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
r, err := s.service.GetReceiver(ctx, q, user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var access *ngmodels.ReceiverPermissionSet
|
||||
var inUse *ngmodels.ReceiverMetadata
|
||||
if fillMetadata {
|
||||
|
||||
accesses, err := s.metadata.AccessControlMetadata(ctx, user, r)
|
||||
if err == nil {
|
||||
if a, ok := accesses[r.GetUID()]; ok {
|
||||
access = &a
|
||||
}
|
||||
} else {
|
||||
return nil, fmt.Errorf("failed to get access control metadata: %w", err)
|
||||
}
|
||||
|
||||
inUses, err := s.metadata.InUseMetadata(ctx, info.OrgID, r)
|
||||
if err == nil {
|
||||
if a, ok := inUses[r.GetUID()]; ok {
|
||||
inUse = &a
|
||||
}
|
||||
} else {
|
||||
return nil, fmt.Errorf("failed to get access control metadata: %w", err)
|
||||
}
|
||||
}
|
||||
return convertToK8sResource(info.OrgID, r, access, inUse, s.namespacer, keepSecrets)
|
||||
}
|
||||
|
||||
func (s *legacyStorage) Create(ctx context.Context,
|
||||
obj runtime.Object,
|
||||
createValidation rest.ValidateObjectFunc,
|
||||
_ *metav1.CreateOptions,
|
||||
) (runtime.Object, error) {
|
||||
info, err := request.NamespaceInfoFrom(ctx, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if createValidation != nil {
|
||||
if err := createValidation(ctx, obj.DeepCopyObject()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
p, ok := obj.(*model.Receiver)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("expected receiver but got %s", obj.GetObjectKind().GroupVersionKind())
|
||||
}
|
||||
if p.Name != "" { // TODO remove when metadata.name can be defined by user
|
||||
return nil, apierrors.NewBadRequest("object's metadata.name should be empty")
|
||||
}
|
||||
model, err := convertToDomainModel(p)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
user, err := identity.GetRequester(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
out, err := s.service.CreateReceiver(ctx, model, info.OrgID, user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return convertToK8sResource(info.OrgID, out, nil, nil, s.namespacer, false)
|
||||
}
|
||||
|
||||
func (s *legacyStorage) Update(ctx context.Context,
|
||||
uid string,
|
||||
objInfo rest.UpdatedObjectInfo,
|
||||
createValidation rest.ValidateObjectFunc,
|
||||
updateValidation rest.ValidateObjectUpdateFunc,
|
||||
_ bool,
|
||||
_ *metav1.UpdateOptions,
|
||||
) (runtime.Object, bool, error) {
|
||||
info, err := request.NamespaceInfoFrom(ctx, true)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
|
||||
user, err := identity.GetRequester(ctx)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
|
||||
old, err := s.get(ctx, uid, true, false)
|
||||
if err != nil {
|
||||
return old, false, err
|
||||
}
|
||||
obj, err := objInfo.UpdatedObject(ctx, old)
|
||||
if err != nil {
|
||||
return old, false, err
|
||||
}
|
||||
if updateValidation != nil {
|
||||
if err := updateValidation(ctx, obj, old); err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
}
|
||||
p, ok := obj.(*model.Receiver)
|
||||
if !ok {
|
||||
return nil, false, fmt.Errorf("expected receiver but got %s", obj.GetObjectKind().GroupVersionKind())
|
||||
}
|
||||
model, err := convertToDomainModel(p)
|
||||
if err != nil {
|
||||
return old, false, err
|
||||
}
|
||||
|
||||
updated, err := s.service.UpdateReceiver(ctx, model, nil, info.OrgID, user)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
|
||||
r, err := convertToK8sResource(info.OrgID, updated, nil, nil, s.namespacer, false)
|
||||
return r, false, err
|
||||
}
|
||||
|
||||
// GracefulDeleter
|
||||
func (s *legacyStorage) Delete(ctx context.Context, uid string, deleteValidation rest.ValidateObjectFunc, options *metav1.DeleteOptions) (runtime.Object, bool, error) {
|
||||
info, err := request.NamespaceInfoFrom(ctx, true)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
|
||||
user, err := identity.GetRequester(ctx)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
|
||||
old, err := s.Get(ctx, uid, nil)
|
||||
if err != nil {
|
||||
return old, false, err
|
||||
}
|
||||
if deleteValidation != nil {
|
||||
if err = deleteValidation(ctx, old); err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
}
|
||||
version := ""
|
||||
if options.Preconditions != nil && options.Preconditions.ResourceVersion != nil {
|
||||
version = *options.Preconditions.ResourceVersion
|
||||
}
|
||||
|
||||
err = s.service.DeleteReceiver(ctx, uid, definitions.Provenance(ngmodels.ProvenanceNone), version, info.OrgID, user) // TODO add support for dry-run option
|
||||
return old, false, err // false - will be deleted async
|
||||
}
|
||||
|
||||
func (s *legacyStorage) DeleteCollection(ctx context.Context, deleteValidation rest.ValidateObjectFunc, options *metav1.DeleteOptions, listOptions *internalversion.ListOptions) (runtime.Object, error) {
|
||||
return nil, apierrors.NewMethodNotSupported(ResourceInfo.GroupResource(), "deleteCollection")
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package v0alpha2
|
||||
|
||||
import (
|
||||
grafanarest "github.com/grafana/grafana/pkg/apiserver/rest"
|
||||
"github.com/grafana/grafana/pkg/services/apiserver/endpoints/request"
|
||||
)
|
||||
|
||||
func NewStorage(
|
||||
legacySvc ReceiverService,
|
||||
namespacer request.NamespaceMapper,
|
||||
metadata MetadataService,
|
||||
) grafanarest.Storage {
|
||||
return &legacyStorage{
|
||||
service: legacySvc,
|
||||
namespacer: namespacer,
|
||||
tableConverter: ResourceInfo.TableConverter(),
|
||||
metadata: metadata,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package v0alpha2
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
|
||||
modelv2 "github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/receiver/v0alpha2"
|
||||
"github.com/grafana/grafana/pkg/apimachinery/utils"
|
||||
)
|
||||
|
||||
var kindV2 = modelv2.Kind()
|
||||
|
||||
var ResourceInfo = utils.NewResourceInfo(kindV2.Group(), kindV2.Version(),
|
||||
kindV2.GroupVersionResource().Resource, strings.ToLower(kindV2.Kind()), kindV2.Kind(),
|
||||
func() runtime.Object { return kindV2.ZeroValue() },
|
||||
func() runtime.Object { return kindV2.ZeroListValue() },
|
||||
utils.TableColumns{
|
||||
Definition: []metav1.TableColumnDefinition{
|
||||
{Name: "Name", Type: "string", Format: "name"},
|
||||
{Name: "Title", Type: "string", Format: "string", Description: "The receiver name"},
|
||||
{Name: "Integrations", Type: "string", Format: "string", Description: "The integration types"},
|
||||
},
|
||||
Reader: func(obj any) ([]interface{}, error) {
|
||||
r, ok := obj.(*modelv2.Receiver)
|
||||
if ok {
|
||||
return []interface{}{
|
||||
r.Name,
|
||||
r.Spec.Title,
|
||||
strings.Join(r.Spec.GetIntegrationsTypes(), ","),
|
||||
}, nil
|
||||
}
|
||||
return nil, fmt.Errorf("expected resource or info")
|
||||
},
|
||||
},
|
||||
)
|
||||
@@ -12,6 +12,8 @@ import (
|
||||
notificationsApp "github.com/grafana/grafana/apps/alerting/notifications/pkg/app"
|
||||
grafanarest "github.com/grafana/grafana/pkg/apiserver/rest"
|
||||
"github.com/grafana/grafana/pkg/registry/apps/alerting/notifications/receiver"
|
||||
receiverv1 "github.com/grafana/grafana/pkg/registry/apps/alerting/notifications/receiver/v0alpha1"
|
||||
receiverv2 "github.com/grafana/grafana/pkg/registry/apps/alerting/notifications/receiver/v0alpha2"
|
||||
"github.com/grafana/grafana/pkg/registry/apps/alerting/notifications/routingtree"
|
||||
"github.com/grafana/grafana/pkg/registry/apps/alerting/notifications/templategroup"
|
||||
"github.com/grafana/grafana/pkg/registry/apps/alerting/notifications/timeinterval"
|
||||
@@ -55,7 +57,8 @@ func getAuthorizer(authz accesscontrol.AccessControl) authorizer.Authorizer {
|
||||
return templategroup.Authorize(ctx, authz, a)
|
||||
case timeinterval.ResourceInfo.GroupResource().Resource:
|
||||
return timeinterval.Authorize(ctx, authz, a)
|
||||
case receiver.ResourceInfo.GroupResource().Resource:
|
||||
case receiverv1.ResourceInfo.GroupResource().Resource,
|
||||
receiverv2.ResourceInfo.GroupResource().Resource:
|
||||
return receiver.Authorize(ctx, ac.NewReceiverAccess[*ngmodels.Receiver](authz, false), a)
|
||||
case routingtree.ResourceInfo.GroupResource().Resource:
|
||||
return routingtree.Authorize(ctx, authz, a)
|
||||
@@ -66,14 +69,16 @@ func getAuthorizer(authz accesscontrol.AccessControl) authorizer.Authorizer {
|
||||
|
||||
func getLegacyStorage(namespacer request.NamespaceMapper, ng *ngalert.AlertNG) runner.LegacyStorageGetter {
|
||||
return func(gvr schema.GroupVersionResource) grafanarest.Storage {
|
||||
if gvr == receiver.ResourceInfo.GroupVersionResource() {
|
||||
return receiver.NewStorage(ng.Api.ReceiverService, namespacer, ng.Api.ReceiverService)
|
||||
if gvr == receiverv1.ResourceInfo.GroupVersionResource() {
|
||||
return receiverv1.NewStorage(ng.Api.ReceiverService, namespacer, ng.Api.ReceiverService)
|
||||
} else if gvr == timeinterval.ResourceInfo.GroupVersionResource() {
|
||||
return timeinterval.NewStorage(ng.Api.MuteTimings, namespacer)
|
||||
} else if gvr == templategroup.ResourceInfo.GroupVersionResource() {
|
||||
return templategroup.NewStorage(ng.Api.Templates, namespacer)
|
||||
} else if gvr == routingtree.ResourceInfo.GroupVersionResource() {
|
||||
return routingtree.NewStorage(ng.Api.Policies, namespacer)
|
||||
} else if gvr == receiverv2.ResourceInfo.GroupVersionResource() {
|
||||
return receiverv2.NewStorage(ng.Api.ReceiverService, namespacer, ng.Api.ReceiverService)
|
||||
}
|
||||
panic("unknown legacy storage requested: " + gvr.String())
|
||||
}
|
||||
|
||||
@@ -71,12 +71,12 @@ func (b *appBuilder) InstallSchema(scheme *runtime.Scheme) error {
|
||||
// Link this group to the internal representation.
|
||||
// This is used for server-side-apply (PATCH), and avoids the error:
|
||||
// "no kind is registered for the type"
|
||||
gvInternal := schema.GroupVersion{
|
||||
Group: gv.Group,
|
||||
Version: runtime.APIVersionInternal,
|
||||
}
|
||||
scheme.AddKnownTypeWithName(gvInternal.WithKind(kind.Kind()), kind.ZeroValue())
|
||||
scheme.AddKnownTypeWithName(gvInternal.WithKind(kind.Kind()+"List"), kind.ZeroListValue())
|
||||
// gvInternal := schema.GroupVersion{
|
||||
// Group: gv.Group,
|
||||
// Version: runtime.APIVersionInternal,
|
||||
// }
|
||||
// scheme.AddKnownTypeWithName(gvInternal.WithKind(kind.Kind()), kind.ZeroValue())
|
||||
// scheme.AddKnownTypeWithName(gvInternal.WithKind(kind.Kind()+"List"), kind.ZeroListValue())
|
||||
|
||||
if len(kind.SelectableFields()) == 0 {
|
||||
continue
|
||||
|
||||
@@ -241,74 +241,6 @@ func (rs *ReceiverService) GetReceivers(ctx context.Context, q models.GetReceive
|
||||
return limitOffset(filtered, q.Offset, q.Limit), nil
|
||||
}
|
||||
|
||||
// ListReceivers returns a list of receivers a user has access to.
|
||||
// Receivers can be filtered by name.
|
||||
// This offers an looser permissions compared to GetReceivers. When a user doesn't have read access it will check for list access instead of returning an empty list.
|
||||
// If the users has list access, all receiver settings will be removed from the response. This option is for backwards compatibility with the v1/receivers endpoint
|
||||
// and should be removed when FGAC is fully implemented.
|
||||
func (rs *ReceiverService) ListReceivers(ctx context.Context, q models.ListReceiversQuery, user identity.Requester) ([]*models.Receiver, error) { // TODO: Remove this method with FGAC.
|
||||
ctx, span := rs.tracer.Start(ctx, "alerting.receivers.list", trace.WithAttributes(
|
||||
attribute.Int64("query_org_id", q.OrgID),
|
||||
attribute.StringSlice("query_names", q.Names),
|
||||
attribute.Int("query_limit", q.Limit),
|
||||
attribute.Int("query_offset", q.Offset),
|
||||
))
|
||||
defer span.End()
|
||||
|
||||
listAccess, err := rs.authz.HasList(ctx, user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
uids := make([]string, 0, len(q.Names))
|
||||
for _, name := range q.Names {
|
||||
uids = append(uids, legacy_storage.NameToUid(name))
|
||||
}
|
||||
|
||||
revision, err := rs.cfgStore.Get(ctx, q.OrgID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
postables := revision.GetReceivers(uids)
|
||||
|
||||
span.AddEvent("Loaded receivers", trace.WithAttributes(
|
||||
attribute.String("concurrency_token", revision.ConcurrencyToken),
|
||||
attribute.Int("count", len(postables)),
|
||||
))
|
||||
|
||||
storedProvenances, err := rs.provisioningStore.GetProvenances(ctx, q.OrgID, (&definitions.EmbeddedContactPoint{}).ResourceType())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
receivers, err := PostableApiReceiversToReceivers(postables, storedProvenances)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !listAccess {
|
||||
var err error
|
||||
receivers, err = rs.authz.FilterRead(ctx, user, receivers...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
span.AddEvent("Applied access control filter", trace.WithAttributes(
|
||||
attribute.Int("count", len(receivers)),
|
||||
))
|
||||
}
|
||||
|
||||
// Remove settings.
|
||||
for _, r := range receivers {
|
||||
for _, integration := range r.Integrations {
|
||||
integration.Settings = nil
|
||||
integration.SecureSettings = nil
|
||||
integration.DisableResolveMessage = false
|
||||
}
|
||||
}
|
||||
|
||||
return limitOffset(receivers, q.Offset, q.Limit), nil
|
||||
}
|
||||
|
||||
// DeleteReceiver deletes a receiver by uid.
|
||||
// UID field currently does not exist, we assume the uid is a particular hashed value of the receiver name.
|
||||
func (rs *ReceiverService) DeleteReceiver(ctx context.Context, uid string, callerProvenance definitions.Provenance, version string, orgID int64, user identity.Requester) error {
|
||||
|
||||
@@ -1740,11 +1740,6 @@
|
||||
}
|
||||
},
|
||||
"x-kubernetes-group-version-kind": [
|
||||
{
|
||||
"group": "advisor.grafana.app",
|
||||
"kind": "Check",
|
||||
"version": "__internal"
|
||||
},
|
||||
{
|
||||
"group": "advisor.grafana.app",
|
||||
"kind": "Check",
|
||||
@@ -1807,11 +1802,6 @@
|
||||
}
|
||||
},
|
||||
"x-kubernetes-group-version-kind": [
|
||||
{
|
||||
"group": "advisor.grafana.app",
|
||||
"kind": "CheckList",
|
||||
"version": "__internal"
|
||||
},
|
||||
{
|
||||
"group": "advisor.grafana.app",
|
||||
"kind": "CheckList",
|
||||
@@ -1953,11 +1943,6 @@
|
||||
}
|
||||
},
|
||||
"x-kubernetes-group-version-kind": [
|
||||
{
|
||||
"group": "advisor.grafana.app",
|
||||
"kind": "CheckType",
|
||||
"version": "__internal"
|
||||
},
|
||||
{
|
||||
"group": "advisor.grafana.app",
|
||||
"kind": "CheckType",
|
||||
@@ -2001,11 +1986,6 @@
|
||||
}
|
||||
},
|
||||
"x-kubernetes-group-version-kind": [
|
||||
{
|
||||
"group": "advisor.grafana.app",
|
||||
"kind": "CheckTypeList",
|
||||
"version": "__internal"
|
||||
},
|
||||
{
|
||||
"group": "advisor.grafana.app",
|
||||
"kind": "CheckTypeList",
|
||||
|
||||
@@ -1741,11 +1741,6 @@
|
||||
}
|
||||
},
|
||||
"x-kubernetes-group-version-kind": [
|
||||
{
|
||||
"group": "investigations.grafana.app",
|
||||
"kind": "Investigation",
|
||||
"version": "__internal"
|
||||
},
|
||||
{
|
||||
"group": "investigations.grafana.app",
|
||||
"kind": "Investigation",
|
||||
@@ -1892,11 +1887,6 @@
|
||||
}
|
||||
},
|
||||
"x-kubernetes-group-version-kind": [
|
||||
{
|
||||
"group": "investigations.grafana.app",
|
||||
"kind": "InvestigationIndex",
|
||||
"version": "__internal"
|
||||
},
|
||||
{
|
||||
"group": "investigations.grafana.app",
|
||||
"kind": "InvestigationIndex",
|
||||
@@ -2031,11 +2021,6 @@
|
||||
}
|
||||
},
|
||||
"x-kubernetes-group-version-kind": [
|
||||
{
|
||||
"group": "investigations.grafana.app",
|
||||
"kind": "InvestigationIndexList",
|
||||
"version": "__internal"
|
||||
},
|
||||
{
|
||||
"group": "investigations.grafana.app",
|
||||
"kind": "InvestigationIndexList",
|
||||
@@ -2218,11 +2203,6 @@
|
||||
}
|
||||
},
|
||||
"x-kubernetes-group-version-kind": [
|
||||
{
|
||||
"group": "investigations.grafana.app",
|
||||
"kind": "InvestigationList",
|
||||
"version": "__internal"
|
||||
},
|
||||
{
|
||||
"group": "investigations.grafana.app",
|
||||
"kind": "InvestigationList",
|
||||
|
||||
@@ -3433,11 +3433,6 @@
|
||||
}
|
||||
},
|
||||
"x-kubernetes-group-version-kind": [
|
||||
{
|
||||
"group": "notifications.alerting.grafana.app",
|
||||
"kind": "Receiver",
|
||||
"version": "__internal"
|
||||
},
|
||||
{
|
||||
"group": "notifications.alerting.grafana.app",
|
||||
"kind": "Receiver",
|
||||
@@ -3481,11 +3476,6 @@
|
||||
}
|
||||
},
|
||||
"x-kubernetes-group-version-kind": [
|
||||
{
|
||||
"group": "notifications.alerting.grafana.app",
|
||||
"kind": "ReceiverList",
|
||||
"version": "__internal"
|
||||
},
|
||||
{
|
||||
"group": "notifications.alerting.grafana.app",
|
||||
"kind": "ReceiverList",
|
||||
@@ -3724,11 +3714,6 @@
|
||||
}
|
||||
},
|
||||
"x-kubernetes-group-version-kind": [
|
||||
{
|
||||
"group": "notifications.alerting.grafana.app",
|
||||
"kind": "RoutingTree",
|
||||
"version": "__internal"
|
||||
},
|
||||
{
|
||||
"group": "notifications.alerting.grafana.app",
|
||||
"kind": "RoutingTree",
|
||||
@@ -3772,11 +3757,6 @@
|
||||
}
|
||||
},
|
||||
"x-kubernetes-group-version-kind": [
|
||||
{
|
||||
"group": "notifications.alerting.grafana.app",
|
||||
"kind": "RoutingTreeList",
|
||||
"version": "__internal"
|
||||
},
|
||||
{
|
||||
"group": "notifications.alerting.grafana.app",
|
||||
"kind": "RoutingTreeList",
|
||||
@@ -3980,11 +3960,6 @@
|
||||
}
|
||||
},
|
||||
"x-kubernetes-group-version-kind": [
|
||||
{
|
||||
"group": "notifications.alerting.grafana.app",
|
||||
"kind": "TemplateGroup",
|
||||
"version": "__internal"
|
||||
},
|
||||
{
|
||||
"group": "notifications.alerting.grafana.app",
|
||||
"kind": "TemplateGroup",
|
||||
@@ -4028,11 +4003,6 @@
|
||||
}
|
||||
},
|
||||
"x-kubernetes-group-version-kind": [
|
||||
{
|
||||
"group": "notifications.alerting.grafana.app",
|
||||
"kind": "TemplateGroupList",
|
||||
"version": "__internal"
|
||||
},
|
||||
{
|
||||
"group": "notifications.alerting.grafana.app",
|
||||
"kind": "TemplateGroupList",
|
||||
@@ -4208,11 +4178,6 @@
|
||||
}
|
||||
},
|
||||
"x-kubernetes-group-version-kind": [
|
||||
{
|
||||
"group": "notifications.alerting.grafana.app",
|
||||
"kind": "TimeInterval",
|
||||
"version": "__internal"
|
||||
},
|
||||
{
|
||||
"group": "notifications.alerting.grafana.app",
|
||||
"kind": "TimeInterval",
|
||||
@@ -4256,11 +4221,6 @@
|
||||
}
|
||||
},
|
||||
"x-kubernetes-group-version-kind": [
|
||||
{
|
||||
"group": "notifications.alerting.grafana.app",
|
||||
"kind": "TimeIntervalList",
|
||||
"version": "__internal"
|
||||
},
|
||||
{
|
||||
"group": "notifications.alerting.grafana.app",
|
||||
"kind": "TimeIntervalList",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -910,11 +910,6 @@
|
||||
}
|
||||
},
|
||||
"x-kubernetes-group-version-kind": [
|
||||
{
|
||||
"group": "playlist.grafana.app",
|
||||
"kind": "Playlist",
|
||||
"version": "__internal"
|
||||
},
|
||||
{
|
||||
"group": "playlist.grafana.app",
|
||||
"kind": "Playlist",
|
||||
@@ -977,11 +972,6 @@
|
||||
}
|
||||
},
|
||||
"x-kubernetes-group-version-kind": [
|
||||
{
|
||||
"group": "playlist.grafana.app",
|
||||
"kind": "PlaylistList",
|
||||
"version": "__internal"
|
||||
},
|
||||
{
|
||||
"group": "playlist.grafana.app",
|
||||
"kind": "PlaylistList",
|
||||
|
||||
@@ -96,6 +96,9 @@ func TestIntegrationOpenAPIs(t *testing.T) {
|
||||
}, {
|
||||
Group: "notifications.alerting.grafana.app",
|
||||
Version: "v0alpha1",
|
||||
}, {
|
||||
Group: "notifications.alerting.grafana.app",
|
||||
Version: "v0alpha2",
|
||||
}}
|
||||
for _, gv := range groups {
|
||||
VerifyOpenAPISnapshots(t, dir, gv, h)
|
||||
|
||||
Reference in New Issue
Block a user