Skip to content

Commit

Permalink
feat: add user-defined context to notifications
Browse files Browse the repository at this point in the history
Signed-off-by: daftping <[email protected]>
  • Loading branch information
daftping committed May 4, 2024
1 parent 125fc3d commit dca652b
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 9 deletions.
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 @@ import (
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 @@ func NewAPIFactorySettings(arInformer argoinformers.AnalysisRunInformer) api.Set
"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 @@ func NewAPIFactorySettings(arInformer argoinformers.AnalysisRunInformer) api.Set

}

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

0 comments on commit dca652b

Please sign in to comment.