Files
flagger/pkg/controller/events.go
2020-08-20 20:56:10 +02:00

196 lines
6.6 KiB
Go

package controller
import (
"context"
"fmt"
"strings"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
corev1 "k8s.io/api/core/v1"
flaggerv1 "github.com/weaveworks/flagger/pkg/apis/flagger/v1beta1"
"github.com/weaveworks/flagger/pkg/notifier"
)
func (c *Controller) recordEventInfof(r *flaggerv1.Canary, template string, args ...interface{}) {
c.logger.With("canary", fmt.Sprintf("%s.%s", r.Name, r.Namespace)).Infof(template, args...)
c.eventRecorder.Event(r, corev1.EventTypeNormal, "Synced", fmt.Sprintf(template, args...))
c.sendEventToWebhook(r, corev1.EventTypeNormal, template, args)
}
func (c *Controller) recordEventErrorf(r *flaggerv1.Canary, template string, args ...interface{}) {
c.logger.With("canary", fmt.Sprintf("%s.%s", r.Name, r.Namespace)).Errorf(template, args...)
c.eventRecorder.Event(r, corev1.EventTypeWarning, "Synced", fmt.Sprintf(template, args...))
c.sendEventToWebhook(r, corev1.EventTypeWarning, template, args)
}
func (c *Controller) recordEventWarningf(r *flaggerv1.Canary, template string, args ...interface{}) {
c.logger.With("canary", fmt.Sprintf("%s.%s", r.Name, r.Namespace)).Infof(template, args...)
c.eventRecorder.Event(r, corev1.EventTypeWarning, "Synced", fmt.Sprintf(template, args...))
c.sendEventToWebhook(r, corev1.EventTypeWarning, template, args)
}
func (c *Controller) sendEventToWebhook(r *flaggerv1.Canary, eventType, template string, args []interface{}) {
webhookOverride := false
for _, canaryWebhook := range r.GetAnalysis().Webhooks {
if canaryWebhook.Type == flaggerv1.EventHook {
webhookOverride = true
err := CallEventWebhook(r, canaryWebhook.URL, fmt.Sprintf(template, args...), eventType)
if err != nil {
c.logger.With("canary", fmt.Sprintf("%s.%s", r.Name, r.Namespace)).Errorf("error sending event to webhook: %s", err)
}
}
}
if c.eventWebhook != "" && !webhookOverride {
err := CallEventWebhook(r, c.eventWebhook, fmt.Sprintf(template, args...), eventType)
if err != nil {
c.logger.With("canary", fmt.Sprintf("%s.%s", r.Name, r.Namespace)).Errorf("error sending event to webhook: %s", err)
}
}
}
func (c *Controller) alert(canary *flaggerv1.Canary, message string, metadata bool, severity flaggerv1.AlertSeverity) {
var fields []notifier.Field
if metadata {
fields = alertMetadata(canary)
}
// send alert with the global notifier
if len(canary.GetAnalysis().Alerts) == 0 {
err := c.notifier.Post(canary.Name, canary.Namespace, message, fields, string(severity))
if err != nil {
c.logger.With("canary", fmt.Sprintf("%s.%s", canary.Name, canary.Namespace)).
Errorf("alert can't be sent: %v", err)
return
}
return
}
// send canary alerts
for _, alert := range canary.GetAnalysis().Alerts {
// determine if alert should be sent based on severity level
shouldAlert := false
if alert.Severity == flaggerv1.SeverityInfo {
shouldAlert = true
} else {
if severity == alert.Severity {
shouldAlert = true
}
if severity == flaggerv1.SeverityWarn && alert.Severity == flaggerv1.SeverityError {
shouldAlert = true
}
}
if !shouldAlert {
continue
}
// determine alert provider namespace
providerNamespace := canary.GetNamespace()
if alert.ProviderRef.Namespace != "" {
providerNamespace = alert.ProviderRef.Namespace
}
// find alert provider
provider, err := c.flaggerInformers.AlertInformer.Lister().AlertProviders(providerNamespace).Get(alert.ProviderRef.Name)
if err != nil {
c.logger.With("canary", fmt.Sprintf("%s.%s", canary.Name, canary.Namespace)).
Errorf("alert provider %s.%s error: %v", alert.ProviderRef.Name, providerNamespace, err)
continue
}
// set hook URL address
url := provider.Spec.Address
// extract address from secret
if provider.Spec.SecretRef != nil {
secret, err := c.kubeClient.CoreV1().Secrets(providerNamespace).Get(context.TODO(), provider.Spec.SecretRef.Name, metav1.GetOptions{})
if err != nil {
c.logger.With("canary", fmt.Sprintf("%s.%s", canary.Name, canary.Namespace)).
Errorf("alert provider %s.%s secretRef error: %v", alert.ProviderRef.Name, providerNamespace, err)
continue
}
if address, ok := secret.Data["address"]; ok {
url = string(address)
} else {
c.logger.With("canary", fmt.Sprintf("%s.%s", canary.Name, canary.Namespace)).
Errorf("alert provider %s.%s secret does not contain an address", alert.ProviderRef.Name, providerNamespace)
continue
}
}
// set defaults
username := "flagger"
if provider.Spec.Username != "" {
username = provider.Spec.Username
}
channel := "general"
if provider.Spec.Channel != "" {
channel = provider.Spec.Channel
}
// create notifier based on provider type
f := notifier.NewFactory(url, username, channel)
n, err := f.Notifier(provider.Spec.Type)
if err != nil {
c.logger.With("canary", fmt.Sprintf("%s.%s", canary.Name, canary.Namespace)).
Errorf("alert provider %s.%s error: %v", alert.ProviderRef.Name, providerNamespace, err)
continue
}
// send alert
err = n.Post(canary.Name, canary.Namespace, message, fields, string(severity))
if err != nil {
c.logger.With("canary", fmt.Sprintf("%s.%s", canary.Name, canary.Namespace)).
Errorf("alert provider $s.%s send error: %v", alert.ProviderRef.Name, providerNamespace, err)
}
}
}
func alertMetadata(canary *flaggerv1.Canary) []notifier.Field {
var fields []notifier.Field
fields = append(fields,
notifier.Field{
Name: "Target",
Value: fmt.Sprintf("%s/%s.%s", canary.Spec.TargetRef.Kind, canary.Spec.TargetRef.Name, canary.Namespace),
},
notifier.Field{
Name: "Failed checks threshold",
Value: fmt.Sprintf("%v", canary.GetAnalysisThreshold()),
},
notifier.Field{
Name: "Progress deadline",
Value: fmt.Sprintf("%vs", canary.GetProgressDeadlineSeconds()),
},
)
if canary.GetAnalysis().StepWeight > 0 {
fields = append(fields, notifier.Field{
Name: "Traffic routing",
Value: fmt.Sprintf("Weight step: %v max: %v",
canary.GetAnalysis().StepWeight,
canary.GetAnalysis().MaxWeight),
})
} else if len(canary.GetAnalysis().StepWeights) > 0 {
fields = append(fields, notifier.Field{
Name: "Traffic routing",
Value: fmt.Sprintf("Weight steps: %s max: %v",
strings.Trim(strings.Join(strings.Fields(fmt.Sprint(canary.GetAnalysis().StepWeights)), ","), "[]"),
canary.GetAnalysis().MaxWeight),
})
} else if len(canary.GetAnalysis().Match) > 0 {
fields = append(fields, notifier.Field{
Name: "Traffic routing",
Value: "A/B Testing",
})
} else if canary.GetAnalysis().Iterations > 0 {
fields = append(fields, notifier.Field{
Name: "Traffic routing",
Value: "Blue/Green",
})
}
return fields
}