Skip to content

Commit

Permalink
implement Pagerduty
Browse files Browse the repository at this point in the history
Co-Authored-By: Yuta Nakano <[email protected]>
  • Loading branch information
keguchi2114 authored and abuthahir80 committed Mar 4, 2022
1 parent 2379691 commit de56cd7
Show file tree
Hide file tree
Showing 8 changed files with 113 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ const alertRecipientLabelMap: any = {
http: 'HTTP',
oc: 'OC',
slack: 'Slack',
opsgenie: 'OpsGenie'
opsgenie: 'OpsGenie',
pagerduty: 'PagerDuty'
};

@Component({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -720,6 +720,15 @@
</mat-form-field>
</div>
</div>
<div class="pager-duty-specific-fields" *ngIf="notificationRecipientsValue && notificationRecipientsValue.pagerduty">
<div class="form-group alert-pagerduty-autoclose">
<div class="form-label vertical-center"><strong>PagerDuty AutoClose</strong></div>
<div class="pagerduty-autoclose-flag">
<mat-checkbox formControlName="pagerdutyAutoClose" value="true"></mat-checkbox>
<mat-hint class="info-hint">Enabling AutoClose will ignore `Send one notification per` setting for PagerDuty. Alerts will be sent per unique tag set.</mat-hint>
</div>
</div>
</div>
</div>
</div>

Expand Down Expand Up @@ -939,6 +948,15 @@
</mat-form-field>
</div>
</div>
<div class="pager-duty-specific-fields" *ngIf="notificationRecipientsValue && notificationRecipientsValue.pagerduty">
<div class="form-group alert-pagerduty-autoclose">
<div class="form-label vertical-center"><strong>PagerDuty AutoClose</strong></div>
<div class="pagerduty-autoclose-flag">
<mat-checkbox formControlName="pagerdutyAutoClose" value="true"></mat-checkbox>
<mat-hint class="info-hint">Enabling AutoClose will ignore `Send one notification per` setting for PagerDuty. Alerts will be sent per unique tag set.</mat-hint>
</div>
</div>
</div>
</div>
</div>

Expand Down Expand Up @@ -1194,6 +1212,15 @@
</div>
</div>
</div>
<div class="pager-duty-specific-fields" *ngIf="notificationRecipientsValue && notificationRecipientsValue.pagerduty">
<div class="form-group alert-pagerduty-autoclose">
<div class="form-label vertical-center"><strong>PagerDuty AutoClose</strong></div>
<div class="pagerduty-autoclose-flag">
<span>{{ data.notification.pagerdutyAutoClose === true ? 'Yes' : 'No' }}</span>
<mat-hint class="info-hint" *ngIf="data.notification.pagerdutyAutoClose === true">Enabling AutoClose will ignore `Send one notification per` setting for Paferduty. Alerts will be sent per unique tag set.</mat-hint>
</div>
</div>
</div>
</div>
</div>
<div class="step-section misc-details is-visible" *ngIf="data.id">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -574,7 +574,9 @@ export class AlertDetailsComponent implements OnInit, OnDestroy, AfterContentIni
// OC conditional values
runbookId: data.notification.runbookId || '',
ocSeverity: data.notification.ocSeverity || this.defaultOCSeverity,
ocTier: data.notification.ocTier || this.defaultOCTier
ocTier: data.notification.ocTier || this.defaultOCTier,
// PagerDuty conditional values
pagerdutyAutoClose: data.notification.pagerdutyAutoClose || false
})
});
this.prevTimeSampler = data.threshold.singleMetric.timeSampler || 'at_least_once';
Expand Down Expand Up @@ -757,7 +759,9 @@ export class AlertDetailsComponent implements OnInit, OnDestroy, AfterContentIni
// OC conditional values
runbookId: data.notification.runbookId || '',
ocSeverity: data.notification.ocSeverity || this.defaultOCSeverity,
ocTier: data.notification.ocTier || this.defaultOCTier
ocTier: data.notification.ocTier || this.defaultOCTier,
// PagerDuty conditional values
pagerdutyAutoClose: data.notification.pagerdutyAutoClose || false
})
});
this.setTags();
Expand Down Expand Up @@ -837,7 +841,9 @@ export class AlertDetailsComponent implements OnInit, OnDestroy, AfterContentIni
opsgenieTags: this.fb.array(data.notification.opsgenieTags || []),
runbookId: data.notification.runbookId || '',
ocSeverity: data.notification.ocSeverity || this.defaultOCSeverity,
ocTier: data.notification.ocTier || this.defaultOCTier
ocTier: data.notification.ocTier || this.defaultOCTier,
// PagerDuty conditional values
pagerdutyAutoClose: data.notification.pagerdutyAutoClose || false
})
});
this.options.axes.y.valueRange[0] = 0;
Expand Down Expand Up @@ -2028,6 +2034,10 @@ export class AlertDetailsComponent implements OnInit, OnDestroy, AfterContentIni
this.alertForm['controls'].notification.get('opsgenieAutoClose').setValue(false);
this.alertForm.get('notification')['controls']['opsgenieTags'] = this.fb.array([]);
}

if (this.notificationRecipients.value.pagerduty && !event.pagerduty) {
this.alertForm['controls'].notification.get('pagerdutyAutoClose').setValue(false);
}
this.notificationRecipients.setValue(event);

}
Expand Down Expand Up @@ -2111,7 +2121,8 @@ export class AlertDetailsComponent implements OnInit, OnDestroy, AfterContentIni
slack: 'Slack',
http: 'Webhook',
oc: 'OC',
email: 'Email'
email: 'Email',
pagerduty: 'PagerDuty'
}
return types[type];
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ export enum RecipientType {
slack = 'slack',
http = 'http',
oc = 'oc',
email = 'email'
email = 'email',
pagerduty = 'pagerduty'
}

export class Recipient {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,38 @@
</mat-form-field>
</div>
</div>

<!--Pager duty Form-->
<div *ngIf="recipientType === _recipientType.pagerduty" class="contacts-create-form">
<div class="form-group">
<div class="form-label vertical-center">Team Name</div>
<mat-form-field floatLabel="never" appearance="fill">
<input matInput [formControl]="pagerDutyName" placeholder="Enter Team Name*" required
minlength="2" maxlength="36" [value]="recipientsFormData[_recipientType.pagerduty].name"
(input)="updateRecipient(recipientsFormData[_recipientType.pagerduty], 'name', $event.target.value)">
<mat-error *ngIf="pagerDutyName.errors && (pagerDutyName.dirty || pagerDutyName.touched)">
Unique Team Name required. Min length is 2. Max length is 36.
</mat-error>
</mat-form-field>
</div>
<div class="form-group">
<div class="form-label vertical-center">Routing Key</div>
<mat-form-field floatLabel="never" appearance="fill" class="wide-formfield">
<input matInput [formControl]="pagerDutyRoutingKey" placeholder="Enter Routing Key*" required
minlength="32" maxlength="32" [value]="recipientsFormData[_recipientType.pagerduty].routingkey"
(input)="updateRecipient(recipientsFormData[_recipientType.pagerduty], 'routingkey', $event.target.value)">
<mat-error *ngIf="pagerDutyRoutingKey.errors && (pagerDutyRoutingKey.dirty || pagerDutyRoutingKey.touched)">
Routing Key required. Length is {{pagerDutyRoutingKeyMaxLength}}.
</mat-error>
</mat-form-field>
</div>
<div class="form-group">
<div class="form-label"></div>
<span>
Follow steps outlined in <a href="{{config.alert.recipient.pagerduty.guideUrl}}" target="_blank">the user-guide</a> to create an API key.
</span>
</div>
</div>
</div>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ export class AlertConfigurationContactsComponent implements OnInit, OnChanges, O
];
slackWebhookMaxLength = 200;
opsGenieApiKeyMaxLength = 200;
pagerDutyRoutingKeyMaxLength = 32;

_mode = Mode; // for template
_recipientType = RecipientType; // for template
Expand All @@ -83,6 +84,8 @@ export class AlertConfigurationContactsComponent implements OnInit, OnChanges, O
httpName = new FormControl('');
httpEndpoint = new FormControl('');
emailAddress = new FormControl('');
pagerDutyName = new FormControl('');
pagerDutyRoutingKey = new FormControl('');

// state control
private nsRecipientSub: Subscription;
Expand Down Expand Up @@ -113,6 +116,10 @@ export class AlertConfigurationContactsComponent implements OnInit, OnChanges, O
if (this.emailAddress.errors) {
return true;
}
} else if (this.recipientType === RecipientType.pagerduty) {
if (this.pagerDutyName.errors || this.pagerDutyRoutingKey.errors) {
return true;
}
}
return false;
}
Expand Down Expand Up @@ -292,6 +299,8 @@ export class AlertConfigurationContactsComponent implements OnInit, OnChanges, O
this.httpName.setValue(this.recipientsFormData[RecipientType.http].name);
this.httpEndpoint.setValue(this.recipientsFormData[RecipientType.http].endpoint);
this.emailAddress.setValue(this.recipientsFormData[RecipientType.email].name);
this.pagerDutyName.setValue(this.recipientsFormData[RecipientType.pagerduty].name);
this.pagerDutyRoutingKey.setValue(this.recipientsFormData[RecipientType.pagerduty].routingkey);
}

addUserInputToAlertRecipients($event: MatChipInputEvent) {
Expand Down Expand Up @@ -473,6 +482,8 @@ export class AlertConfigurationContactsComponent implements OnInit, OnChanges, O
return 'OC';
} else if (type === RecipientType.email) {
return 'Email';
} else if (type === RecipientType.pagerduty) {
return 'PagerDuty';
}
return '';
}
Expand All @@ -484,6 +495,7 @@ export class AlertConfigurationContactsComponent implements OnInit, OnChanges, O
let emptyHTTPRecipient = this.createDefaultRecipient(RecipientType.http);
let emptyOCRecipient = this.createDefaultRecipient(RecipientType.oc);
let emptyEmailRecipient = this.createDefaultRecipient(RecipientType.email);
let emptyPagerDutyRecipient = this.createDefaultRecipient(RecipientType.pagerduty);

// Set Defaults
emptyOpsGenieRecipient.apikey = '';
Expand All @@ -493,12 +505,14 @@ export class AlertConfigurationContactsComponent implements OnInit, OnChanges, O
emptyOCRecipient.context = 'analysis';
emptyOCRecipient.opsdbproperty = '';
emptyEmailRecipient.name = '';
emptyPagerDutyRecipient.routingkey = '';

emptyRecipients[RecipientType.opsgenie] = emptyOpsGenieRecipient;
emptyRecipients[RecipientType.slack] = emptySlackRecipient;
emptyRecipients[RecipientType.http] = emptyHTTPRecipient;
emptyRecipients[RecipientType.oc] = emptyOCRecipient;
emptyRecipients[RecipientType.email] = emptyEmailRecipient;
emptyRecipients[RecipientType.pagerduty] = emptyPagerDutyRecipient;
this.recipientsFormData = emptyRecipients;
}

Expand Down Expand Up @@ -534,6 +548,10 @@ export class AlertConfigurationContactsComponent implements OnInit, OnChanges, O
return apiKey && apiKey.length > 0 && apiKey.length <= this.opsGenieApiKeyMaxLength;
}

isPagerDutyRoutingKeyCorrectLength(routingkey: string): boolean {
return routingkey && routingkey.length > 0 && routingkey.length <= this.pagerDutyRoutingKeyMaxLength;
}

getRecipientItemsByType(type) {
if (this.viewMode === Mode.all) {
// all mode (show only unselected)
Expand Down Expand Up @@ -619,6 +637,13 @@ export class AlertConfigurationContactsComponent implements OnInit, OnChanges, O
};
}

pagerDutyRoutingKeyValidator(): ValidatorFn {
return (control: AbstractControl): { [key: string]: any } | null => {
let forbidden = !this.isPagerDutyRoutingKeyCorrectLength(control.value);
return forbidden ? {'forbiddenName': {value: control.value}} : null;
};
}

urlValidator() : ValidatorFn {
return (control: AbstractControl): { [key: string]: any } | null => {
let forbidden = !/^https:\/\/(www\.)?(([-a-zA-Z0-9@:%._[\]]{1,256}\.[a-zA-Z0-9()]{0,6}\b)|(\[?[a-fA-F0-9]*:[a-fA-F0-9:]+\]))([-a-zA-Z0-9()@:%_\+.~#?&//=]*)$/.test(control.value);
Expand All @@ -636,6 +661,8 @@ export class AlertConfigurationContactsComponent implements OnInit, OnChanges, O
this.ocName = new FormControl('', [this.forbiddenNameValidator(this.getAllRecipientsForType(RecipientType.oc), this.recipientsFormData[this.recipientType])]);
this.httpName = new FormControl('', [this.forbiddenNameValidator(this.getAllRecipientsForType(RecipientType.http), this.recipientsFormData[this.recipientType])]);
this.emailAddress = new FormControl('', [this.forbiddenNameValidator(this.getAllRecipientsForType(RecipientType.email), this.recipientsFormData[this.recipientType]), this.emailValidator()]);
this.pagerDutyName = new FormControl('', [this.forbiddenNameValidator(this.getAllRecipientsForType(RecipientType.pagerduty), this.recipientsFormData[this.recipientType])]);
this.pagerDutyRoutingKey = new FormControl('', [this.pagerDutyRoutingKeyValidator()]);
}

trimRecipientName(name) {
Expand Down
4 changes: 3 additions & 1 deletion frontend/src/app/alerts/containers/alerts.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,7 @@ export class AlertsComponent implements OnInit, OnDestroy, AfterViewChecked {
this.sparklineDisplay = this.sparklineDisplayMenuOptions[0];

// icons
const svgIcons = ['email', 'http', 'oc', 'opsgenie', 'slack'];
const svgIcons = ['email', 'http', 'oc', 'opsgenie', 'slack', 'pagerduty'];

}

Expand Down Expand Up @@ -1391,6 +1391,8 @@ export class AlertsComponent implements OnInit, OnDestroy, AfterViewChecked {
return 'OC';
} else if (type === RecipientType.email) {
return 'Email';
} else if (type === RecipientType.pagerduty) {
return 'PagerDuty';
}
return '';
}
Expand Down
6 changes: 5 additions & 1 deletion server/config/app_config.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,18 @@
},
"oc": {
"enable": false,
"onboardUrl": "<% OC onboad url %>",
"onboardUrl": "<% OC onboard url %>",
"guideUrl": "<% OC guide url %>"
},
"http": {
"enable": false
},
"email": {
"enable": true
},
"pagerduty": {
"enable": false,
"guideUrl": "<% pagerduty guide url %>"
}
}
},
Expand Down

0 comments on commit de56cd7

Please sign in to comment.