Skip to content

Commit

Permalink
Merge pull request #176 from LWJ/sentry_provider
Browse files Browse the repository at this point in the history
Add support for Sentry provider
  • Loading branch information
stefanprodan authored Mar 29, 2021
2 parents ae810e6 + f946908 commit 1fa3d2f
Show file tree
Hide file tree
Showing 8 changed files with 256 additions and 4 deletions.
3 changes: 2 additions & 1 deletion api/v1beta1/provider_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ const (
// ProviderSpec defines the desired state of Provider
type ProviderSpec struct {
// Type of provider
// +kubebuilder:validation:Enum=slack;discord;msteams;rocket;generic;github;gitlab;bitbucket;azuredevops;googlechat;webex
// +kubebuilder:validation:Enum=slack;discord;msteams;rocket;generic;github;gitlab;bitbucket;azuredevops;googlechat;webex;sentry
// +required
Type string `json:"type"`

Expand Down Expand Up @@ -70,6 +70,7 @@ const (
AzureDevOpsProvider string = "azuredevops"
GoogleChatProvider string = "googlechat"
WebexProvider string = "webex"
SentryProvider string = "sentry"
)

// ProviderStatus defines the observed state of Provider
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ spec:
- azuredevops
- googlechat
- webex
- sentry
type: string
username:
description: Bot username for this provider
Expand Down
3 changes: 2 additions & 1 deletion docs/spec/v1beta1/provider.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ Notification providers:
* Rocket
* Google Chat
* Webex
* Sentry
* Generic webhook

Git commit status providers:
Expand Down Expand Up @@ -105,7 +106,7 @@ kubectl create secret generic webhook-url \

Note that the secret must contain an `address` field.

The provider type can be: `slack`, `msteams`, `rocket`, `discord`, `googlechat`, `webex`, `github`, `gitlab`, `bitbucket`, `azuredevops` or `generic`.
The provider type can be: `slack`, `msteams`, `rocket`, `discord`, `googlechat`, `webex`, `sentry`, `github`, `gitlab`, `bitbucket`, `azuredevops` or `generic`.

When type `generic` is specified, the notification controller will post the
incoming [event](event.md) in JSON format to the webhook address.
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ require (
github.com/fluxcd/notification-controller/api v0.11.0
github.com/fluxcd/pkg/apis/meta v0.8.0
github.com/fluxcd/pkg/runtime v0.10.1
github.com/getsentry/sentry-go v0.10.0
github.com/go-logr/logr v0.3.0
github.com/google/go-github/v32 v32.1.0
github.com/hashicorp/go-retryablehttp v0.6.8
Expand Down
108 changes: 106 additions & 2 deletions go.sum

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions internal/notifier/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ func (f Factory) Notifier(provider string) (Interface, error) {
n, err = NewGoogleChat(f.URL, f.ProxyURL)
case v1beta1.WebexProvider:
n, err = NewWebex(f.URL, f.ProxyURL)
case v1beta1.SentryProvider:
n, err = NewSentry(f.URL)
default:
err = fmt.Errorf("provider %s not supported", provider)
}
Expand Down
74 changes: 74 additions & 0 deletions internal/notifier/sentry.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
Copyright 2020 The Flux authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package notifier

import (
"fmt"
"github.com/fluxcd/pkg/runtime/events"
"github.com/getsentry/sentry-go"
)

// Sentry holds the client instance
type Sentry struct {
Client *sentry.Client
}

// NewSentry creates a Sentry client from the provided Data Source Name (DSN)
func NewSentry(dsn string) (*Sentry, error) {
client, err := sentry.NewClient(sentry.ClientOptions{
Dsn: dsn,
})
if err != nil {
return nil, err
}

return &Sentry{
Client: client,
}, nil
}

// Post event to Sentry
func (s *Sentry) Post(event events.Event) error {
// Skip any update events
if isCommitStatus(event.Metadata, "update") {
return nil
}

// Send event to Sentry
s.Client.CaptureEvent(toSentryEvent(event), nil, nil)
return nil
}

// Maps a controller-issued event to a Sentry event
func toSentryEvent(event events.Event) *sentry.Event {
// Prepare Metadata
extra := make(map[string]interface{}, len(event.Metadata))
for k, v := range event.Metadata {
extra[k] = v
}

// Construct event
obj := event.InvolvedObject
return &sentry.Event{
Timestamp: event.Timestamp.Time,
Level: sentry.Level(event.Severity),
ServerName: event.ReportingController,
Transaction: fmt.Sprintf("%s: %s/%s", obj.Kind, obj.Namespace, obj.Name),
Extra: extra,
Message: event.Message,
}
}
68 changes: 68 additions & 0 deletions internal/notifier/sentry_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
Copyright 2020 The Flux authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package notifier

import (
"github.com/fluxcd/pkg/runtime/events"
"github.com/getsentry/sentry-go"
"github.com/stretchr/testify/assert"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"testing"
"time"

"github.com/stretchr/testify/require"
)

func TestNewSentry(t *testing.T) {
s, err := NewSentry("https://test@localhost/1")
require.NoError(t, err)
assert.Equal(t, s.Client.Options().Dsn, "https://test@localhost/1")
}

func TestToSentryEvent(t *testing.T) {
// Construct test event
e := events.Event{
InvolvedObject: corev1.ObjectReference{
Kind: "GitRepository",
Namespace: "flux-system",
Name: "test-app",
},
Severity: "info",
Timestamp: metav1.Date(2020, 01, 01, 0, 0, 0, 0, time.UTC),
Message: "message",
Metadata: map[string]string{
"key1": "val1",
"key2": "val2",
},
ReportingController: "source-controller",
}

// Map to Sentry event
s := toSentryEvent(e)

// Assertions
assert.Equal(t, time.Date(2020, 01, 01, 0, 0, 0, 0, time.UTC), s.Timestamp)
assert.Equal(t, sentry.LevelInfo, s.Level)
assert.Equal(t, "source-controller", s.ServerName)
assert.Equal(t, "GitRepository: flux-system/test-app", s.Transaction)
assert.Equal(t, map[string]interface{}{
"key1": "val1",
"key2": "val2",
}, s.Extra)
assert.Equal(t, "message", s.Message)
}

0 comments on commit 1fa3d2f

Please sign in to comment.