Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add user-defined context to notifications #3553

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
20 changes: 19 additions & 1 deletion docs/features/notifications.md
Original file line number Diff line number Diff line change
Expand Up @@ -160,9 +160,27 @@ data:

Each condition might use several templates. Typically each template is responsible for generating a service-specific notification part.

### User-defined context

It is possible to define some shared context between all notification templates by setting a top-level YAML document of key-value pairs, which can then be used within templates, like so:

```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: argo-rollouts-notification-configmap
data:
context: |
region: east
environmentName: staging

template.a-slack-template-with-context: |
message: "Something happened in {{ .context.environmentName }} in the {{ .context.region }} data center!"
```

### Notification Metrics

The following prometheus metrics are emitted when notifications are enabled in argo-rollouts.
- notification_send_success is a counter that measures how many times the notification is sent successfully.
- notification_send_error is a counter that measures how many times the notification failed to send.
- notification_send is a histogram that measures performance of sending notification.
- notification_send is a histogram that measures performance of sending notification.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ require (
google.golang.org/grpc v1.63.2
google.golang.org/protobuf v1.34.0
gopkg.in/yaml.v2 v2.4.0
gopkg.in/yaml.v3 v3.0.1
k8s.io/api v0.29.3
k8s.io/apiextensions-apiserver v0.29.3
k8s.io/apimachinery v0.29.3
Expand Down Expand Up @@ -221,7 +222,6 @@ require (
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/cloud-provider v0.0.0 // indirect
k8s.io/cluster-bootstrap v0.25.8 // indirect
k8s.io/component-helpers v0.29.3 // indirect
Expand Down
21 changes: 15 additions & 6 deletions utils/record/record.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
rolloutscheme "github.com/argoproj/argo-rollouts/pkg/client/clientset/versioned/scheme"
"github.com/argoproj/argo-rollouts/utils/annotations"
logutil "github.com/argoproj/argo-rollouts/utils/log"
"gopkg.in/yaml.v3"
)

func init() {
Expand Down Expand Up @@ -318,6 +319,18 @@
"secrets": secret.Data,
}

if contextData, ok := configMap.Data["context"]; ok {
var contextMap map[string]string
err := yaml.Unmarshal([]byte(contextData), &contextMap)
if err != nil {
log.Warnf("Failed to unmarshal 'context' key from %s: %v", NotificationConfigMap, err)

Check warning on line 326 in utils/record/record.go

View check run for this annotation

Codecov / codecov/patch

utils/record/record.go#L326

Added line #L326 was not covered by tests
} else {
vars["context"] = contextMap
}
} else {
log.Debugf("The key 'context' is not present in the %s", NotificationConfigMap)
}

if arInformer == nil {
log.Infof("Notification is not set for analysisRun Informer: %s", dest)
return vars
Expand All @@ -340,12 +353,8 @@

}

vars = map[string]any{
"rollout": obj,
"analysisRuns": arsObj,
"time": timeExprs,
"secrets": secret.Data,
}
vars["analysisRuns"] = arsObj

return vars
}, nil
},
Expand Down
30 changes: 29 additions & 1 deletion utils/record/record_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -509,6 +509,7 @@ func TestNewAPIFactorySettings(t *testing.T) {
name string
arInformer arInformerFunc
rollout v1alpha1.Rollout
cm corev1.ConfigMap
ars []*v1alpha1.AnalysisRun
expected expectedFunc
}{
Expand All @@ -518,6 +519,7 @@ func TestNewAPIFactorySettings(t *testing.T) {
return createAnalysisRunInformer(ars)
},
rollout: ro,
cm: corev1.ConfigMap{},
ars: ars,
expected: func(obj map[string]interface{}, ar any) map[string]interface{} {
return map[string]interface{}{
Expand All @@ -534,6 +536,7 @@ func TestNewAPIFactorySettings(t *testing.T) {
return createAnalysisRunInformer(ars)
},
rollout: ro,
cm: corev1.ConfigMap{},
ars: []*v1alpha1.AnalysisRun{
{
ObjectMeta: metav1.ObjectMeta{
Expand All @@ -560,6 +563,7 @@ func TestNewAPIFactorySettings(t *testing.T) {
return nil
},
rollout: ro,
cm: corev1.ConfigMap{},
ars: nil,
expected: func(obj map[string]interface{}, ar any) map[string]interface{} {
return map[string]interface{}{
Expand All @@ -575,6 +579,7 @@ func TestNewAPIFactorySettings(t *testing.T) {
return createAnalysisRunInformer(ars)
},
rollout: ro,
cm: corev1.ConfigMap{},
ars: []*v1alpha1.AnalysisRun{
{
ObjectMeta: metav1.ObjectMeta{
Expand All @@ -595,13 +600,36 @@ func TestNewAPIFactorySettings(t *testing.T) {
}
},
},
{
name: "Send notification with context",
arInformer: func(ars []*v1alpha1.AnalysisRun) argoinformers.AnalysisRunInformer {
return nil
},
rollout: ro,
cm: corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: NotificationConfigMap,
Namespace: "argo-rollouts",
},
Data: map[string]string{"context": "server: foo\nenv: prod"},
},
ars: nil,
expected: func(obj map[string]interface{}, ar any) map[string]interface{} {
return map[string]interface{}{
"rollout": obj,
"time": timeExprs,
"secrets": expectedSecrets,
"context": map[string]string{"server": "foo", "env": "prod"},
}
},
},
}

for _, test := range testcase {
t.Run(test.name, func(t *testing.T) {

settings := NewAPIFactorySettings(test.arInformer(test.ars))
getVars, err := settings.InitGetVars(nil, nil, &notificationsSecret)
getVars, err := settings.InitGetVars(nil, &test.cm, &notificationsSecret)
require.NoError(t, err)
if err != nil {
t.Errorf("Unexpected error: %v", err)
Expand Down