Improve notification mechanism
This commit is contained in:
		
							parent
							
								
									364ce8ad8a
								
							
						
					
					
						commit
						9bde4cb59f
					
				|  | @ -3,11 +3,10 @@ package notifier | ||||||
| import ( | import ( | ||||||
| 	"context" | 	"context" | ||||||
| 	"fmt" | 	"fmt" | ||||||
|  | 	"github.com/pkg/errors" | ||||||
| 	"time" | 	"time" | ||||||
| 
 | 
 | ||||||
| 	"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2" | 	"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2" | ||||||
| 	"github.com/jenkinsci/kubernetes-operator/pkg/log" |  | ||||||
| 
 |  | ||||||
| 	"github.com/mailgun/mailgun-go/v3" | 	"github.com/mailgun/mailgun-go/v3" | ||||||
| 	corev1 "k8s.io/api/core/v1" | 	corev1 "k8s.io/api/core/v1" | ||||||
| 	"k8s.io/apimachinery/pkg/types" | 	"k8s.io/apimachinery/pkg/types" | ||||||
|  | @ -44,21 +43,19 @@ type Mailgun struct{} | ||||||
| 
 | 
 | ||||||
| // Send is function for sending directly to API
 | // Send is function for sending directly to API
 | ||||||
| func (m Mailgun) Send(n *Notification, config v1alpha2.Notification) error { | func (m Mailgun) Send(n *Notification, config v1alpha2.Notification) error { | ||||||
| 	var selector v1alpha2.SecretKeySelector |  | ||||||
| 	secret := &corev1.Secret{} | 	secret := &corev1.Secret{} | ||||||
| 	i := n.Information | 	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) | 	err := n.K8sClient.Get(context.TODO(), types.NamespacedName{Name: selector.Name, Namespace: n.Jenkins.Namespace}, secret) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		n.Logger.V(log.VWarn).Info(fmt.Sprintf("Failed to get secret with name `%s`. %+v", selector.Name, err)) |  | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	secretValue := string(secret.Data[selector.Name]) | 	secretValue := string(secret.Data[selector.Name]) | ||||||
| 	if secretValue == "" { | 	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) | 	mg := mailgun.NewMailgun(config.Mailgun.Domain, secretValue) | ||||||
|  |  | ||||||
|  | @ -4,12 +4,10 @@ import ( | ||||||
| 	"bytes" | 	"bytes" | ||||||
| 	"context" | 	"context" | ||||||
| 	"encoding/json" | 	"encoding/json" | ||||||
| 	"fmt" | 	"github.com/pkg/errors" | ||||||
| 	"net/http" | 	"net/http" | ||||||
| 
 | 
 | ||||||
| 	"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2" | 	"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2" | ||||||
| 	"github.com/jenkinsci/kubernetes-operator/pkg/log" |  | ||||||
| 
 |  | ||||||
| 	corev1 "k8s.io/api/core/v1" | 	corev1 "k8s.io/api/core/v1" | ||||||
| 	"k8s.io/apimachinery/pkg/types" | 	"k8s.io/apimachinery/pkg/types" | ||||||
| ) | ) | ||||||
|  | @ -40,15 +38,14 @@ type TeamsFact struct { | ||||||
| 
 | 
 | ||||||
| // Send is function for sending directly to API
 | // Send is function for sending directly to API
 | ||||||
| func (t Teams) Send(n *Notification, config v1alpha2.Notification) error { | func (t Teams) Send(n *Notification, config v1alpha2.Notification) error { | ||||||
| 	var selector v1alpha2.SecretKeySelector |  | ||||||
| 	secret := &corev1.Secret{} | 	secret := &corev1.Secret{} | ||||||
| 	i := n.Information | 	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) | 	err := n.K8sClient.Get(context.TODO(), types.NamespacedName{Name: selector.Name, Namespace: n.Jenkins.Namespace}, secret) | ||||||
| 	if err != nil { | 	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{ | 	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]) | 	secretValue := string(secret.Data[selector.Key]) | ||||||
| 	if secretValue == "" { | 	if secretValue == "" { | ||||||
| 		return fmt.Errorf("SecretValue %s is empty", selector.Name) | 		return errors.Errorf("SecretValue %s is empty", selector.Name) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
|  |  | ||||||
|  | @ -2,9 +2,9 @@ package notifier | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"github.com/go-logr/logr" |  | ||||||
| 	"net/http" | 	"net/http" | ||||||
| 
 | 
 | ||||||
|  | 	"github.com/go-logr/logr" | ||||||
| 	"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2" | 	"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2" | ||||||
| 	"github.com/jenkinsci/kubernetes-operator/pkg/log" | 	"github.com/jenkinsci/kubernetes-operator/pkg/log" | ||||||
| 
 | 
 | ||||||
|  | @ -70,7 +70,8 @@ type service interface { | ||||||
| // Listen is goroutine that listens for incoming messages and sends it
 | // Listen is goroutine that listens for incoming messages and sends it
 | ||||||
| func Listen(notification chan *Notification) { | func Listen(notification chan *Notification) { | ||||||
| 	for n := range notification { | 	for n := range notification { | ||||||
| 		notificationConfig := n.Jenkins.Spec.Notification | 		if len(n.Jenkins.Spec.Notifications) > 0 { | ||||||
|  | 			for _, notificationConfig := range n.Jenkins.Spec.Notifications { | ||||||
| 				var err error | 				var err error | ||||||
| 				var svc service | 				var svc service | ||||||
| 
 | 
 | ||||||
|  | @ -93,6 +94,8 @@ func Listen(notification chan *Notification) { | ||||||
| 					n.Logger.V(log.VDebug).Info("Sent notification") | 					n.Logger.V(log.VDebug).Info("Sent notification") | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func getStatusColor(logLevel LoggingLevel, svc service) StatusColor { | func getStatusColor(logLevel LoggingLevel, svc service) StatusColor { | ||||||
|  | @ -129,16 +132,10 @@ func getStatusColor(logLevel LoggingLevel, svc service) StatusColor { | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func notify(svc service, n *Notification, nc v1alpha2.Notification) error { | func notify(svc service, n *Notification, manifest v1alpha2.Notification) error { | ||||||
| 	var err error | 	if n.Information.LogLevel == LogInfo && string(manifest.LoggingLevel) == string(LogWarn) { | ||||||
| 	switch s := svc.(type) { | 		return nil | ||||||
| 	case Slack: |  | ||||||
| 		err = s.Send(n, nc) |  | ||||||
| 	case Teams: |  | ||||||
| 		err = s.Send(n, nc) |  | ||||||
| 	case Mailgun: |  | ||||||
| 		err = s.Send(n, nc) |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return err | 	return svc.Send(n, manifest) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -4,12 +4,10 @@ import ( | ||||||
| 	"bytes" | 	"bytes" | ||||||
| 	"context" | 	"context" | ||||||
| 	"encoding/json" | 	"encoding/json" | ||||||
| 	"fmt" | 	"github.com/pkg/errors" | ||||||
| 	"net/http" | 	"net/http" | ||||||
| 
 | 
 | ||||||
| 	"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2" | 	"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2" | ||||||
| 	"github.com/jenkinsci/kubernetes-operator/pkg/log" |  | ||||||
| 
 |  | ||||||
| 	corev1 "k8s.io/api/core/v1" | 	corev1 "k8s.io/api/core/v1" | ||||||
| 	"k8s.io/apimachinery/pkg/types" | 	"k8s.io/apimachinery/pkg/types" | ||||||
| ) | ) | ||||||
|  | @ -43,15 +41,14 @@ type SlackField struct { | ||||||
| 
 | 
 | ||||||
| // Send is function for sending directly to API
 | // Send is function for sending directly to API
 | ||||||
| func (s Slack) Send(n *Notification, config v1alpha2.Notification) error { | func (s Slack) Send(n *Notification, config v1alpha2.Notification) error { | ||||||
| 	var selector v1alpha2.SecretKeySelector |  | ||||||
| 	secret := &corev1.Secret{} | 	secret := &corev1.Secret{} | ||||||
| 	i := n.Information | 	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) | 	err := n.K8sClient.Get(context.TODO(), types.NamespacedName{Name: selector.Name, Namespace: n.Jenkins.Namespace}, secret) | ||||||
| 	if err != nil { | 	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{ | 	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]) | 	secretValue := string(secret.Data[selector.Key]) | ||||||
| 	if secretValue == "" { | 	if secretValue == "" { | ||||||
| 		return fmt.Errorf("SecretValue %s is empty", selector.Name) | 		return errors.Errorf("SecretValue %s is empty", selector.Name) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
|  |  | ||||||
|  | @ -17,9 +17,9 @@ type JenkinsSpec struct { | ||||||
| 	// +optional
 | 	// +optional
 | ||||||
| 	SeedJobs []SeedJob `json:"seedJobs,omitempty"` | 	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
 | 	// 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
 | 	// Service is Kubernetes service of Jenkins master HTTP pod
 | ||||||
| 	// Defaults to :
 | 	// Defaults to :
 | ||||||
|  | @ -66,13 +66,13 @@ type Notification struct { | ||||||
| 
 | 
 | ||||||
| // Slack is handler for Slack
 | // Slack is handler for Slack
 | ||||||
| type Slack struct { | type Slack struct { | ||||||
| 	// The web hook url to Slack App
 | 	// The web hook URL to Slack App
 | ||||||
| 	URLSecretKeySelector SecretKeySelector `json:"urlSecretKeySelector"` | 	URLSecretKeySelector SecretKeySelector `json:"urlSecretKeySelector"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Teams is handler for Microsoft Teams
 | // Teams is handler for Microsoft Teams
 | ||||||
| type Teams struct { | type Teams struct { | ||||||
| 	// The web hook url to Teams App
 | 	// The web hook URL to Teams App
 | ||||||
| 	URLSecretKeySelector SecretKeySelector `json:"urlSecretKeySelector"` | 	URLSecretKeySelector SecretKeySelector `json:"urlSecretKeySelector"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -366,7 +366,11 @@ func (in *JenkinsSpec) DeepCopyInto(out *JenkinsSpec) { | ||||||
| 		*out = make([]SeedJob, len(*in)) | 		*out = make([]SeedJob, len(*in)) | ||||||
| 		copy(*out, *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.Service.DeepCopyInto(&out.Service) | ||||||
| 	in.SlaveService.DeepCopyInto(&out.SlaveService) | 	in.SlaveService.DeepCopyInto(&out.SlaveService) | ||||||
| 	in.Backup.DeepCopyInto(&out.Backup) | 	in.Backup.DeepCopyInto(&out.Backup) | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue