Improve notification mechanism

This commit is contained in:
Jakub Al-Khalili 2019-08-02 14:07:37 +02:00
parent 364ce8ad8a
commit 9bde4cb59f
6 changed files with 46 additions and 54 deletions

View File

@ -3,11 +3,10 @@ package notifier
import (
"context"
"fmt"
"github.com/pkg/errors"
"time"
"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2"
"github.com/jenkinsci/kubernetes-operator/pkg/log"
"github.com/mailgun/mailgun-go/v3"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/types"
@ -44,21 +43,19 @@ type Mailgun struct{}
// Send is function for sending directly to API
func (m Mailgun) Send(n *Notification, config v1alpha2.Notification) error {
var selector v1alpha2.SecretKeySelector
secret := &corev1.Secret{}
i := n.Information
selector = config.Mailgun.APIKeySecretKeySelector
selector := config.Mailgun.APIKeySecretKeySelector
err := n.K8sClient.Get(context.TODO(), types.NamespacedName{Name: selector.Name, Namespace: n.Jenkins.Namespace}, secret)
if err != nil {
n.Logger.V(log.VWarn).Info(fmt.Sprintf("Failed to get secret with name `%s`. %+v", selector.Name, err))
return err
}
secretValue := string(secret.Data[selector.Name])
if secretValue == "" {
return fmt.Errorf("SecretValue %s is empty", selector.Name)
return errors.Errorf("SecretValue %s is empty", selector.Name)
}
mg := mailgun.NewMailgun(config.Mailgun.Domain, secretValue)

View File

@ -4,12 +4,10 @@ import (
"bytes"
"context"
"encoding/json"
"fmt"
"github.com/pkg/errors"
"net/http"
"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2"
"github.com/jenkinsci/kubernetes-operator/pkg/log"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/types"
)
@ -40,15 +38,14 @@ type TeamsFact struct {
// Send is function for sending directly to API
func (t Teams) Send(n *Notification, config v1alpha2.Notification) error {
var selector v1alpha2.SecretKeySelector
secret := &corev1.Secret{}
i := n.Information
selector = config.Teams.URLSecretKeySelector
selector := config.Teams.URLSecretKeySelector
err := n.K8sClient.Get(context.TODO(), types.NamespacedName{Name: selector.Name, Namespace: n.Jenkins.Namespace}, secret)
if err != nil {
n.Logger.V(log.VWarn).Info(fmt.Sprintf("Failed to get secret with name `%s`. %+v", selector.Name, err))
return err
}
msg, err := json.Marshal(TeamsMessage{
@ -83,7 +80,7 @@ func (t Teams) Send(n *Notification, config v1alpha2.Notification) error {
secretValue := string(secret.Data[selector.Key])
if secretValue == "" {
return fmt.Errorf("SecretValue %s is empty", selector.Name)
return errors.Errorf("SecretValue %s is empty", selector.Name)
}
if err != nil {

View File

@ -2,9 +2,9 @@ package notifier
import (
"fmt"
"github.com/go-logr/logr"
"net/http"
"github.com/go-logr/logr"
"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2"
"github.com/jenkinsci/kubernetes-operator/pkg/log"
@ -70,27 +70,30 @@ type service interface {
// Listen is goroutine that listens for incoming messages and sends it
func Listen(notification chan *Notification) {
for n := range notification {
notificationConfig := n.Jenkins.Spec.Notification
var err error
var svc service
if len(n.Jenkins.Spec.Notifications) > 0 {
for _, notificationConfig := range n.Jenkins.Spec.Notifications {
var err error
var svc service
if notificationConfig.Slack != (v1alpha2.Slack{}) {
svc = Slack{}
} else if notificationConfig.Teams != (v1alpha2.Teams{}) {
svc = Teams{}
} else if notificationConfig.Mailgun != (v1alpha2.Mailgun{}) {
svc = Mailgun{}
} else {
n.Logger.V(log.VWarn).Info(fmt.Sprintf("Notification service in `%s` not found or not defined", notificationConfig.Name))
continue
}
if notificationConfig.Slack != (v1alpha2.Slack{}) {
svc = Slack{}
} else if notificationConfig.Teams != (v1alpha2.Teams{}) {
svc = Teams{}
} else if notificationConfig.Mailgun != (v1alpha2.Mailgun{}) {
svc = Mailgun{}
} else {
n.Logger.V(log.VWarn).Info(fmt.Sprintf("Notification service in `%s` not found or not defined", notificationConfig.Name))
continue
}
err = notify(svc, n, notificationConfig)
err = notify(svc, n, notificationConfig)
if err != nil {
n.Logger.V(log.VWarn).Info(fmt.Sprintf("Failed to send notifications. %+v", err))
} else {
n.Logger.V(log.VDebug).Info("Sent notification")
if err != nil {
n.Logger.V(log.VWarn).Info(fmt.Sprintf("Failed to send notifications. %+v", err))
} else {
n.Logger.V(log.VDebug).Info("Sent notification")
}
}
}
}
}
@ -129,16 +132,10 @@ func getStatusColor(logLevel LoggingLevel, svc service) StatusColor {
}
}
func notify(svc service, n *Notification, nc v1alpha2.Notification) error {
var err error
switch s := svc.(type) {
case Slack:
err = s.Send(n, nc)
case Teams:
err = s.Send(n, nc)
case Mailgun:
err = s.Send(n, nc)
func notify(svc service, n *Notification, manifest v1alpha2.Notification) error {
if n.Information.LogLevel == LogInfo && string(manifest.LoggingLevel) == string(LogWarn) {
return nil
}
return err
return svc.Send(n, manifest)
}

View File

@ -4,12 +4,10 @@ import (
"bytes"
"context"
"encoding/json"
"fmt"
"github.com/pkg/errors"
"net/http"
"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2"
"github.com/jenkinsci/kubernetes-operator/pkg/log"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/types"
)
@ -43,15 +41,14 @@ type SlackField struct {
// Send is function for sending directly to API
func (s Slack) Send(n *Notification, config v1alpha2.Notification) error {
var selector v1alpha2.SecretKeySelector
secret := &corev1.Secret{}
i := n.Information
selector = config.Slack.URLSecretKeySelector
selector := config.Slack.URLSecretKeySelector
err := n.K8sClient.Get(context.TODO(), types.NamespacedName{Name: selector.Name, Namespace: n.Jenkins.Namespace}, secret)
if err != nil {
n.Logger.V(log.VWarn).Info(fmt.Sprintf("Failed to get secret with name `%s`. %+v", selector.Name, err))
return err
}
slackMessage, err := json.Marshal(SlackMessage{
@ -94,7 +91,7 @@ func (s Slack) Send(n *Notification, config v1alpha2.Notification) error {
secretValue := string(secret.Data[selector.Key])
if secretValue == "" {
return fmt.Errorf("SecretValue %s is empty", selector.Name)
return errors.Errorf("SecretValue %s is empty", selector.Name)
}
if err != nil {

View File

@ -17,9 +17,9 @@ type JenkinsSpec struct {
// +optional
SeedJobs []SeedJob `json:"seedJobs,omitempty"`
// Notification defines services which are used to inform about Jenkins behavior
// Notifications defines services which are used to inform about Jenkins status
// Can be used to integrate chat services like Slack or Email services like Mailgun
Notification Notification `json:"notifications,omitempty"`
Notifications []Notification `json:"notifications,omitempty"`
// Service is Kubernetes service of Jenkins master HTTP pod
// Defaults to :
@ -66,13 +66,13 @@ type Notification struct {
// Slack is handler for Slack
type Slack struct {
// The web hook url to Slack App
// The web hook URL to Slack App
URLSecretKeySelector SecretKeySelector `json:"urlSecretKeySelector"`
}
// Teams is handler for Microsoft Teams
type Teams struct {
// The web hook url to Teams App
// The web hook URL to Teams App
URLSecretKeySelector SecretKeySelector `json:"urlSecretKeySelector"`
}

View File

@ -366,7 +366,11 @@ func (in *JenkinsSpec) DeepCopyInto(out *JenkinsSpec) {
*out = make([]SeedJob, len(*in))
copy(*out, *in)
}
out.Notification = in.Notification
if in.Notifications != nil {
in, out := &in.Notifications, &out.Notifications
*out = make([]Notification, len(*in))
copy(*out, *in)
}
in.Service.DeepCopyInto(&out.Service)
in.SlaveService.DeepCopyInto(&out.SlaveService)
in.Backup.DeepCopyInto(&out.Backup)