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: enable self service notification support #2869

Closed
wants to merge 13 commits into from
10 changes: 5 additions & 5 deletions cmd/rollouts-controller/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,12 +151,12 @@ func newCommand() *cobra.Command {
}
istioDynamicInformerFactory := dynamicinformer.NewFilteredDynamicSharedInformerFactory(istioPrimaryDynamicClient, resyncDuration, namespace, nil)

controllerNamespaceInformerFactory := kubeinformers.NewSharedInformerFactoryWithOptions(
controllerClusterInformerFactory := kubeinformers.NewSharedInformerFactoryWithOptions(
kubeClient,
resyncDuration,
kubeinformers.WithNamespace(defaults.Namespace()))
configMapInformer := controllerNamespaceInformerFactory.Core().V1().ConfigMaps()
secretInformer := controllerNamespaceInformerFactory.Core().V1().Secrets()
)
configMapInformer := controllerClusterInformerFactory.Core().V1().ConfigMaps()
secretInformer := controllerClusterInformerFactory.Core().V1().Secrets()

mode, err := ingressutil.DetermineIngressMode(ingressVersion, kubeClient.DiscoveryClient)
checkError(err)
Expand Down Expand Up @@ -196,7 +196,7 @@ func newCommand() *cobra.Command {
istioDynamicInformerFactory,
namespaced,
kubeInformerFactory,
controllerNamespaceInformerFactory,
controllerClusterInformerFactory,
jobInformerFactory)

if err = cm.Run(ctx, rolloutThreads, serviceThreads, ingressThreads, experimentThreads, analysisThreads, electOpts); err != nil {
Expand Down
94 changes: 47 additions & 47 deletions controller/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,14 +154,14 @@ type Manager struct {

namespace string

dynamicInformerFactory dynamicinformer.DynamicSharedInformerFactory
clusterDynamicInformerFactory dynamicinformer.DynamicSharedInformerFactory
istioDynamicInformerFactory dynamicinformer.DynamicSharedInformerFactory
namespaced bool
kubeInformerFactory kubeinformers.SharedInformerFactory
controllerNamespaceInformerFactory kubeinformers.SharedInformerFactory
jobInformerFactory kubeinformers.SharedInformerFactory
istioPrimaryDynamicClient dynamic.Interface
dynamicInformerFactory dynamicinformer.DynamicSharedInformerFactory
clusterDynamicInformerFactory dynamicinformer.DynamicSharedInformerFactory
istioDynamicInformerFactory dynamicinformer.DynamicSharedInformerFactory
namespaced bool
kubeInformerFactory kubeinformers.SharedInformerFactory
controllerClusterInformerFactory kubeinformers.SharedInformerFactory
jobInformerFactory kubeinformers.SharedInformerFactory
istioPrimaryDynamicClient dynamic.Interface
}

// NewManager returns a new manager to manage all the controllers
Expand Down Expand Up @@ -198,7 +198,7 @@ func NewManager(
istioDynamicInformerFactory dynamicinformer.DynamicSharedInformerFactory,
namespaced bool,
kubeInformerFactory kubeinformers.SharedInformerFactory,
controllerNamespaceInformerFactory kubeinformers.SharedInformerFactory,
controllerClusterInformerFactory kubeinformers.SharedInformerFactory,
jobInformerFactory kubeinformers.SharedInformerFactory,
) *Manager {

Expand Down Expand Up @@ -226,7 +226,7 @@ func NewManager(
refResolver := rollout.NewInformerBasedWorkloadRefResolver(namespace, dynamicclientset, discoveryClient, argoprojclientset, rolloutsInformer.Informer())
apiFactory := notificationapi.NewFactory(record.NewAPIFactorySettings(), defaults.Namespace(), secretInformer.Informer(), configMapInformer.Informer())
recorder := record.NewEventRecorder(kubeclientset, metrics.MetricRolloutEventsTotal, metrics.MetricNotificationFailedTotal, metrics.MetricNotificationSuccessTotal, metrics.MetricNotificationSend, apiFactory)
notificationsController := notificationcontroller.NewController(dynamicclientset.Resource(v1alpha1.RolloutGVR), rolloutsInformer.Informer(), apiFactory,
notificationsController := notificationcontroller.NewControllerWithNamespaceSupport(dynamicclientset.Resource(v1alpha1.RolloutGVR), rolloutsInformer.Informer(), apiFactory,
notificationcontroller.WithToUnstructured(func(obj metav1.Object) (*unstructured.Unstructured, error) {
data, err := json.Marshal(obj)
if err != nil {
Expand Down Expand Up @@ -320,42 +320,42 @@ func NewManager(
})

cm := &Manager{
wg: &sync.WaitGroup{},
metricsServer: metricsServer,
healthzServer: healthzServer,
rolloutSynced: rolloutsInformer.Informer().HasSynced,
serviceSynced: servicesInformer.Informer().HasSynced,
ingressSynced: ingressWrap.HasSynced,
jobSynced: jobInformer.Informer().HasSynced,
experimentSynced: experimentsInformer.Informer().HasSynced,
analysisRunSynced: analysisRunInformer.Informer().HasSynced,
analysisTemplateSynced: analysisTemplateInformer.Informer().HasSynced,
clusterAnalysisTemplateSynced: clusterAnalysisTemplateInformer.Informer().HasSynced,
replicasSetSynced: replicaSetInformer.Informer().HasSynced,
configMapSynced: configMapInformer.Informer().HasSynced,
secretSynced: secretInformer.Informer().HasSynced,
rolloutWorkqueue: rolloutWorkqueue,
experimentWorkqueue: experimentWorkqueue,
analysisRunWorkqueue: analysisRunWorkqueue,
serviceWorkqueue: serviceWorkqueue,
ingressWorkqueue: ingressWorkqueue,
rolloutController: rolloutController,
serviceController: serviceController,
ingressController: ingressController,
experimentController: experimentController,
analysisController: analysisController,
notificationsController: notificationsController,
refResolver: refResolver,
namespace: namespace,
kubeClientSet: kubeclientset,
dynamicInformerFactory: dynamicInformerFactory,
clusterDynamicInformerFactory: clusterDynamicInformerFactory,
istioDynamicInformerFactory: istioDynamicInformerFactory,
namespaced: namespaced,
kubeInformerFactory: kubeInformerFactory,
controllerNamespaceInformerFactory: controllerNamespaceInformerFactory,
jobInformerFactory: jobInformerFactory,
istioPrimaryDynamicClient: istioPrimaryDynamicClient,
wg: &sync.WaitGroup{},
metricsServer: metricsServer,
healthzServer: healthzServer,
rolloutSynced: rolloutsInformer.Informer().HasSynced,
serviceSynced: servicesInformer.Informer().HasSynced,
ingressSynced: ingressWrap.HasSynced,
jobSynced: jobInformer.Informer().HasSynced,
experimentSynced: experimentsInformer.Informer().HasSynced,
analysisRunSynced: analysisRunInformer.Informer().HasSynced,
analysisTemplateSynced: analysisTemplateInformer.Informer().HasSynced,
clusterAnalysisTemplateSynced: clusterAnalysisTemplateInformer.Informer().HasSynced,
replicasSetSynced: replicaSetInformer.Informer().HasSynced,
configMapSynced: configMapInformer.Informer().HasSynced,
secretSynced: secretInformer.Informer().HasSynced,
rolloutWorkqueue: rolloutWorkqueue,
experimentWorkqueue: experimentWorkqueue,
analysisRunWorkqueue: analysisRunWorkqueue,
serviceWorkqueue: serviceWorkqueue,
ingressWorkqueue: ingressWorkqueue,
rolloutController: rolloutController,
serviceController: serviceController,
ingressController: ingressController,
experimentController: experimentController,
analysisController: analysisController,
notificationsController: notificationsController,
refResolver: refResolver,
namespace: namespace,
kubeClientSet: kubeclientset,
dynamicInformerFactory: dynamicInformerFactory,
clusterDynamicInformerFactory: clusterDynamicInformerFactory,
istioDynamicInformerFactory: istioDynamicInformerFactory,
namespaced: namespaced,
kubeInformerFactory: kubeInformerFactory,
controllerClusterInformerFactory: controllerClusterInformerFactory,
jobInformerFactory: jobInformerFactory,
istioPrimaryDynamicClient: istioPrimaryDynamicClient,
}

_, err := rolloutsConfig.InitializeConfig(kubeclientset, defaults.DefaultRolloutsConfigMapName)
Expand Down Expand Up @@ -470,7 +470,7 @@ func (c *Manager) startLeading(ctx context.Context, rolloutThreadiness, serviceT
c.clusterDynamicInformerFactory.Start(ctx.Done())
}
c.kubeInformerFactory.Start(ctx.Done())
c.controllerNamespaceInformerFactory.Start(ctx.Done())
c.controllerClusterInformerFactory.Start(ctx.Done())
c.jobInformerFactory.Start(ctx.Done())

// Check if Istio installed on cluster before starting dynamicInformerFactory
Expand Down
2 changes: 1 addition & 1 deletion controller/controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ func (f *fixture) newManager(t *testing.T) *Manager {
cm.dynamicInformerFactory = dynamicInformerFactory
cm.clusterDynamicInformerFactory = dynamicInformerFactory
cm.kubeInformerFactory = k8sI
cm.controllerNamespaceInformerFactory = k8sI
cm.controllerClusterInformerFactory = k8sI
cm.jobInformerFactory = k8sI
cm.istioPrimaryDynamicClient = dynamicClient
cm.istioDynamicInformerFactory = dynamicInformerFactory
Expand Down
14 changes: 14 additions & 0 deletions docs/features/notifications.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,20 @@ stringData:

Learn more about supported services and configuration settings in services [documentation](../generated/notification-services/overview.md).

## Namespace based configuration

!!! important
Available since v1.6

A common installation method for Argo Rollouts is to install it in a dedicated namespace to manage a whole cluster. In this case, the administrator is the only
person who can configure notifications in that namespace generally. However, in some cases, it is required to allow end-users to configure notifications
for their Rollout resources. For example, the end-user can configure notifications for their Rollouts in the namespace where they have access to and their rollout is running in.

To use this feature all you need to do is create the same configmap named `argo-rollouts-notification-configmap` and possibly
a secrete `argo-rollouts-notification-secret` in the namespace where the rollout object lives. When it is configured this way the controller
will send notifications using both the controller level configuration aka the configmap located in the same namespaces as the controller
as well as the namespace level configuration where the rollout object is at.

## Default Trigger templates

Currently the following triggers have [built-in templates](https://github.com/argoproj/argo-rollouts/tree/master/manifests/notifications).
Expand Down
2 changes: 1 addition & 1 deletion docs/generated/notification-services/email.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ data:

## Template

Notification templates support specifying subject for email notifications:
[Notification templates](../templates.md) support specifying subject for email notifications:

```yaml
apiVersion: v1
Expand Down
8 changes: 7 additions & 1 deletion docs/generated/notification-services/github.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ The GitHub notification service changes commit status using [GitHub Apps](https:
## Configuration

1. Create a GitHub Apps using https://github.com/settings/apps/new
2. Change repository permissions to enable write commit statuses
2. Change repository permissions to enable write commit statuses and/or deployments
![2](https://user-images.githubusercontent.com/18019529/108397381-3ca57980-725b-11eb-8d17-5b8992dc009e.png)
3. Generate a private key, and download it automatically
![3](https://user-images.githubusercontent.com/18019529/108397926-d4a36300-725b-11eb-83fe-74795c8c3e03.png)
Expand Down Expand Up @@ -69,6 +69,12 @@ template.app-deployed: |
state: success
label: "continuous-delivery/{{.app.metadata.name}}"
targetURL: "{{.context.argocdUrl}}/applications/{{.app.metadata.name}}?operation=true"
deployment:
state: success
environment: production
environmentURL: "https://{{.app.metadata.name}}.example.com"
logURL: "{{.context.argocdUrl}}/applications/{{.app.metadata.name}}?operation=true"
requiredContexts: []
```

**Notes**:
Expand Down
4 changes: 2 additions & 2 deletions docs/generated/notification-services/pagerduty.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ data:

## Template

Notification templates support specifying subject for pagerduty notifications:
[Notification templates](../templates.md) support specifying subject for pagerduty notifications:

```yaml
apiVersion: v1
Expand Down Expand Up @@ -63,4 +63,4 @@ kind: Rollout
metadata:
annotations:
notifications.argoproj.io/subscribe.on-rollout-aborted.pagerduty: "<serviceID for Pagerduty>"
```
```
78 changes: 78 additions & 0 deletions docs/generated/notification-services/pagerduty_v2.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# PagerDuty V2

## Parameters

The PagerDuty notification service is used to trigger PagerDuty events and requires specifying the following settings:

* `serviceKeys` - a dictionary with the following structure:
* `service-name: $pagerduty-key-service-name` where `service-name` is the name you want to use for the service to make events for, and `$pagerduty-key-service-name` is a reference to the secret that contains the actual PagerDuty integration key (Events API v2 integration)

If you want multiple Argo apps to trigger events to their respective PagerDuty services, create an integration key in each service you want to setup alerts for.

To create a PagerDuty integration key, [follow these instructions](https://support.pagerduty.com/docs/services-and-integrations#create-a-generic-events-api-integration) to add an Events API v2 integration to the service of your choice.

## Configuration

The following snippet contains sample PagerDuty service configuration. It assumes the service you want to alert on is called `my-service`.

```yaml
apiVersion: v1
kind: Secret
metadata:
name: <secret-name>
stringData:
pagerduty-key-my-service: <pd-integration-key>
```

```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: <config-map-name>
data:
service.pagerdutyv2: |
serviceKeys:
my-service: $pagerduty-key-my-service
```

## Template

[Notification templates](../templates.md) support specifying subject for PagerDuty notifications:

```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: <config-map-name>
data:
template.rollout-aborted: |
message: Rollout {{.rollout.metadata.name}} is aborted.
pagerdutyv2:
summary: "Rollout {{.rollout.metadata.name}} is aborted."
severity: "critical"
source: "{{.rollout.metadata.name}}"
```

The parameters for the PagerDuty configuration in the template generally match with the payload for the Events API v2 endpoint. All parameters are strings.

* `summary` - (required) A brief text summary of the event, used to generate the summaries/titles of any associated alerts.
* `severity` - (required) The perceived severity of the status the event is describing with respect to the affected system. Allowed values: `critical`, `warning`, `error`, `info`
* `source` - (required) The unique location of the affected system, preferably a hostname or FQDN.
* `component` - Component of the source machine that is responsible for the event.
* `group` - Logical grouping of components of a service.
* `class` - The class/type of the event.
* `url` - The URL that should be used for the link "View in ArgoCD" in PagerDuty.

The `timestamp` and `custom_details` parameters are not currently supported.

## Annotation

Annotation sample for PagerDuty notifications:

```yaml
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
annotations:
notifications.argoproj.io/subscribe.on-rollout-aborted.pagerdutyv2: "<serviceID for Pagerduty>"
```
2 changes: 1 addition & 1 deletion docs/generated/notification-services/rocketchat.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ metadata:

## Templates

Notification templates can be customized with RocketChat [attachments](https://developer.rocket.chat/api/rest-api/methods/chat/postmessage#attachments-detail).
[Notification templates](../templates.md) can be customized with RocketChat [attachments](https://developer.rocket.chat/api/rest-api/methods/chat/postmessage#attachments-detail).

*Note: Attachments structure in Rocketchat is same with Slack attachments [feature](https://api.slack.com/messaging/composing/layouts).*

Expand Down
6 changes: 3 additions & 3 deletions docs/generated/notification-services/slack.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ The Slack notification service configuration includes following settings:
token: $slack-token
```

1. Add annotation in application yaml file to enable notifications for specific argocd app
1. Add annotation in application yaml file to enable notifications for specific argocd app. The following example uses the [on-sync-succeeded trigger](../catalog.md#triggers):

```yaml
apiVersion: argoproj.io/v1alpha1
Expand All @@ -60,7 +60,7 @@ The Slack notification service configuration includes following settings:
notifications.argoproj.io/subscribe.on-sync-succeeded.slack: my_channel
```

1. Annotation with more than one trigger multiple of destinations and recipients
1. Annotation with more than one [trigger](../catalog.md#triggers), with multiple destinations and recipients

```yaml
apiVersion: argoproj.io/v1alpha1
Expand All @@ -82,7 +82,7 @@ The Slack notification service configuration includes following settings:

## Templates

Notification templates can be customized to leverage slack message blocks and attachments
[Notification templates](../templates.md) can be customized to leverage slack message blocks and attachments
[feature](https://api.slack.com/messaging/composing/layouts).

![](https://user-images.githubusercontent.com/426437/72776856-6dcef880-3bc8-11ea-8e3b-c72df16ee8e6.png)
Expand Down
4 changes: 2 additions & 2 deletions docs/generated/notification-services/teams.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ metadata:

![](https://user-images.githubusercontent.com/18019529/114271500-9d2b8880-9a4c-11eb-85c1-f6935f0431d5.png)

Notification templates can be customized to leverage teams message sections, facts, themeColor, summary and potentialAction [feature](https://docs.microsoft.com/en-us/microsoftteams/platform/webhooks-and-connectors/how-to/connectors-using).
[Notification templates](../templates.md) can be customized to leverage teams message sections, facts, themeColor, summary and potentialAction [feature](https://docs.microsoft.com/en-us/microsoftteams/platform/webhooks-and-connectors/how-to/connectors-using).

```yaml
template.app-sync-succeeded: |
Expand Down Expand Up @@ -123,4 +123,4 @@ You can set a summary of the message that will be shown on Notifcation & Activit
template.app-sync-succeeded: |
teams:
summary: "Sync Succeeded"
```
```
Loading
Loading