feat(ui): allow customising ack silence comment

Fixes #2369
This commit is contained in:
Łukasz Mierzwa
2020-11-24 19:52:56 +00:00
committed by Łukasz Mierzwa
parent 4598bbb067
commit 2b963c65d1
22 changed files with 74 additions and 50 deletions
+3
View File
@@ -11,3 +11,6 @@
- ghcr.io/prymitive/karma is now used as the primary repository for docker
images instead of Docker Hub
- `alertAcknowledgement:commentPrefix` config option was replaced by
`alertAcknowledgement:comment` that can be used to customise the entire
comment.
@@ -12,7 +12,7 @@ env ALERTMANAGER_TIMEOUT=10s
env ALERTACKNOWLEDGEMENT_ENABLED=true
env ALERTACKNOWLEDGEMENT_DURATION=5m
env ALERTACKNOWLEDGEMENT_AUTHOR=karma
env ALERTACKNOWLEDGEMENT_COMMENTPREFIX=ACK
env ALERTACKNOWLEDGEMENT_COMMENT="ACK! This alert was acknowledged via unit tests"
env ANNOTATIONS_DEFAULT_HIDDEN=true
env ANNOTATIONS_HIDDEN='help summary'
@@ -106,7 +106,7 @@ level=info msg="alertAcknowledgement:"
level=info msg=" enabled: true"
level=info msg=" duration: 5m0s"
level=info msg=" author: karma"
level=info msg=" commentPrefix: ACK"
level=info msg=" comment: '\"ACK!'"
level=info msg="annotations:"
level=info msg=" default:"
level=info msg=" hidden: true"
@@ -93,7 +93,7 @@ level=info msg="alertAcknowledgement:"
level=info msg=" enabled: true"
level=info msg=" duration: 7m0s"
level=info msg=" author: karma"
level=info msg=" commentPrefix: ACK!"
level=info msg=" comment: ACK! This is comment"
level=info msg="annotations:"
level=info msg=" default:"
level=info msg=" hidden: true"
@@ -261,7 +261,7 @@ alertAcknowledgement:
enabled: true
duration: 7m0s
author: karma
commentPrefix: ACK!
comment: ACK! This is comment
annotations:
default:
hidden: true
@@ -37,7 +37,7 @@ alertAcknowledgement:
enabled: zzz
duration: 7m0s
author: karma
commentPrefix: ACK!
comment: comment
annotations:
default:
hidden: z
@@ -39,7 +39,7 @@ level=info msg="alertAcknowledgement:"
level=info msg=" enabled: false"
level=info msg=" duration: 15m0s"
level=info msg=" author: karma"
level=info msg=" commentPrefix: ACK!"
level=info msg=" comment: ACK! This alert was acknowledged using karma on %NOW%"
level=info msg="annotations:"
level=info msg=" default:"
level=info msg=" hidden: false"
+1 -1
View File
@@ -39,7 +39,7 @@ level=info msg="alertAcknowledgement:"
level=info msg=" enabled: false"
level=info msg=" duration: 15m0s"
level=info msg=" author: karma"
level=info msg=" commentPrefix: ACK!"
level=info msg=" comment: ACK! This alert was acknowledged using karma on %NOW%"
level=info msg="annotations:"
level=info msg=" default:"
level=info msg=" hidden: false"
+1 -1
View File
@@ -39,7 +39,7 @@ level=info msg="alertAcknowledgement:"
level=info msg=" enabled: false"
level=info msg=" duration: 15m0s"
level=info msg=" author: karma"
level=info msg=" commentPrefix: ACK!"
level=info msg=" comment: ACK! This alert was acknowledged using karma on %NOW%"
level=info msg="annotations:"
level=info msg=" default:"
level=info msg=" hidden: false"
+1 -1
View File
@@ -41,7 +41,7 @@ level=info msg="alertAcknowledgement:"
level=info msg=" enabled: false"
level=info msg=" duration: 15m0s"
level=info msg=" author: karma"
level=info msg=" commentPrefix: ACK!"
level=info msg=" comment: ACK! This alert was acknowledged using karma on %NOW%"
level=info msg="annotations:"
level=info msg=" default:"
level=info msg=" hidden: false"
@@ -39,7 +39,7 @@ level=info msg="alertAcknowledgement:"
level=info msg=" enabled: false"
level=info msg=" duration: 15m0s"
level=info msg=" author: karma"
level=info msg=" commentPrefix: ACK!"
level=info msg=" comment: ACK! This alert was acknowledged using karma on %NOW%"
level=info msg="annotations:"
level=info msg=" default:"
level=info msg=" hidden: false"
+1 -1
View File
@@ -167,7 +167,7 @@ func alerts(w http.ResponseWriter, r *http.Request) {
Enabled: config.Config.AlertAcknowledgement.Enabled,
DurationSeconds: int(config.Config.AlertAcknowledgement.Duration.Seconds()),
Author: config.Config.AlertAcknowledgement.Author,
CommentPrefix: config.Config.AlertAcknowledgement.CommentPrefix,
Comment: config.Config.AlertAcknowledgement.Comment,
},
}
resp.Authentication = models.AuthenticationInfo{
+1 -1
View File
@@ -857,7 +857,7 @@ func TestEmptySettings(t *testing.T) {
Enabled: false,
DurationSeconds: 900,
Author: "karma",
CommentPrefix: "ACK!",
Comment: "ACK! This alert was acknowledged using karma on %NOW%",
},
}
-1
View File
@@ -28,7 +28,6 @@ alertAcknowledgement:
enabled: true
duration: 15m0s
author: karma-ack
commentPrefix: ACK!
annotations:
hidden:
- help
+15 -5
View File
@@ -412,7 +412,7 @@ alertAcknowledgement:
enabled: bool
duration: duration
author: string
commentPrefix: string
comment: string
```
- `enabled` - setting it to true will enable creation of short lived
@@ -421,8 +421,8 @@ alertAcknowledgement:
[time.Duration](https://golang.org/pkg/time/#ParseDuration) format.
- `author` - default author for acknowledgement silences. If user set the
author field on the silence form then that value will be used instead.
- `commentPrefix` - a string that will be added as a prefix to autogenerated
silence comment (optional).
- `comment` - custom comment used for acknowledgement silences (optional).
If the comment contains `%NOW%` it will be replaced by current timestamp.
Defaults:
@@ -431,7 +431,17 @@ alertAcknowledgement:
enabled: false
duration: 15m0s
author: karma
commentPrefix: ACK!
comment: ACK! This alert was acknowledged using karma
```
Example with timestamp in the comment:
```YAML
alertAcknowledgement:
enabled: false
duration: 15m0s
author: karma
comment: ACK! This alert was acknowledged using karma on %NOW%
```
A common problem is setting a correct duration for the silence.
@@ -446,7 +456,7 @@ short lived acknowledgement silences if there are alerts firing against those
silences, which means that the user doesn't need to worry about setting proper
duration for such silences.
To use it run an instance of kthxbye with every alertmanager instance or
cluster and configure it to use the same comment prefix as `commentPrefix`.
cluster and configure it to use the same comment prefix in `comment`.
With this setup when user clicks to acknowledge an alert karma will create
a short lived silence and kthxbye will keep that silence in Alertmanager
until there are no alerts matching it, meaning that the issue was resolved.
+3 -3
View File
@@ -58,7 +58,7 @@ func SetupFlags(f *pflag.FlagSet) {
f.Bool("alertAcknowledgement.enabled", false, "Enable alert acknowledging")
f.Duration("alertAcknowledgement.duration", time.Minute*15, "Initial silence duration when acknowledging alerts with short lived silences")
f.String("alertAcknowledgement.author", "karma", "Default silence author when acknowledging alerts with short lived silences")
f.String("alertAcknowledgement.commentPrefix", "ACK!", "Comment prefix used when acknowledging alerts with short lived silences")
f.String("alertAcknowledgement.comment", "ACK! This alert was acknowledged using karma on %NOW%", "Comment used when acknowledging alerts with short lived silences")
f.String("authorization.acl.silences", "", "Path to silence ACL config file")
@@ -193,8 +193,8 @@ func readEnvVariables(k *koanf.Koanf) {
return "alertAcknowledgement.duration"
case "ALERTACKNOWLEDGEMENT_AUTHOR":
return "alertAcknowledgement.author"
case "ALERTACKNOWLEDGEMENT_COMMENTPREFIX":
return "alertAcknowledgement.commentPrefix"
case "ALERTACKNOWLEDGEMENT_COMMENT":
return "alertAcknowledgement.comment"
case "AUTHENTICATION_HEADER_VALUE_RE":
return "authentication.header.value_re"
case "SILENCEFORM_STRIP_LABELS":
+1 -1
View File
@@ -52,7 +52,7 @@ alertAcknowledgement:
enabled: false
duration: 15m0s
author: karma
commentPrefix: ACK!
comment: ACK! This alert was acknowledged using karma on %NOW%
annotations:
default:
hidden: true
+4 -4
View File
@@ -81,10 +81,10 @@ type configSchema struct {
CORS AlertmanagerCORS `yaml:"-" koanf:"cors"`
}
AlertAcknowledgement struct {
Enabled bool
Duration time.Duration
Author string
CommentPrefix string `yaml:"commentPrefix" koanf:"commentPrefix"`
Enabled bool
Duration time.Duration
Author string
Comment string
} `yaml:"alertAcknowledgement" koanf:"alertAcknowledgement"`
Annotations struct {
Default struct {
+1 -1
View File
@@ -281,7 +281,7 @@ type AlertAcknowledgementSettings struct {
Enabled bool `json:"enabled"`
DurationSeconds int `json:"durationSeconds"`
Author string `json:"author"`
CommentPrefix string `json:"commentPrefix"`
Comment string `json:"comment"`
}
// Settings is used to export karma configuration that is used by UI
+28 -14
View File
@@ -31,7 +31,7 @@ beforeEach(() => {
enabled: true,
durationSeconds: 123,
author: "default author",
commentPrefix: "PREFIX",
comment: "COMMENT",
};
alertStore.data.setUpstreams({
counters: { total: 1, healthy: 1, failed: 0 },
@@ -284,8 +284,7 @@ describe("<AlertAck />", () => {
silenceFormStore.data.setAuthor("karma/ui");
await MountAndClick();
expect(JSON.parse((fetchMock.lastOptions() as any).body)).toEqual({
comment:
"PREFIX This alert was acknowledged using karma on Tue, 01 Feb 2000 00:00:00 GMT",
comment: "COMMENT",
createdBy: "karma/ui",
endsAt: "2000-02-01T00:02:03.000Z",
matchers: [
@@ -299,11 +298,29 @@ describe("<AlertAck />", () => {
it("uses settings when generating payload", async () => {
alertStore.settings.values.alertAcknowledgement.durationSeconds = 237;
alertStore.settings.values.alertAcknowledgement.author = "me";
alertStore.settings.values.alertAcknowledgement.commentPrefix = "";
alertStore.settings.values.alertAcknowledgement.comment = "comment";
await MountAndClick();
expect(JSON.parse((fetchMock.lastOptions() as any).body)).toEqual({
comment: "comment",
createdBy: "me",
endsAt: "2000-02-01T00:03:57.000Z",
matchers: [
{ isRegex: false, name: "alertname", value: "Fake Alert" },
{ isRegex: true, name: "foo", value: "(bar|baz)" },
],
startsAt: "2000-02-01T00:00:00.000Z",
});
});
it("injects timestamp when configured", async () => {
alertStore.settings.values.alertAcknowledgement.durationSeconds = 237;
alertStore.settings.values.alertAcknowledgement.author = "me";
alertStore.settings.values.alertAcknowledgement.comment =
"ACK! This alert was acknowledged using karma on %NOW%";
await MountAndClick();
expect(JSON.parse((fetchMock.lastOptions() as any).body)).toEqual({
comment:
"This alert was acknowledged using karma on Tue, 01 Feb 2000 00:00:00 GMT",
"ACK! This alert was acknowledged using karma on Tue, 01 Feb 2000 00:00:00 GMT",
createdBy: "me",
endsAt: "2000-02-01T00:03:57.000Z",
matchers: [
@@ -319,11 +336,10 @@ describe("<AlertAck />", () => {
alertStore.info.authentication.username = "auth@example.com";
alertStore.settings.values.alertAcknowledgement.durationSeconds = 222;
alertStore.settings.values.alertAcknowledgement.author = "me";
alertStore.settings.values.alertAcknowledgement.commentPrefix = "FOO:";
alertStore.settings.values.alertAcknowledgement.comment = "FOO: bar";
await MountAndClick();
expect(JSON.parse((fetchMock.lastOptions() as any).body)).toEqual({
comment:
"FOO: This alert was acknowledged using karma on Tue, 01 Feb 2000 00:00:00 GMT",
comment: "FOO: bar",
createdBy: "auth@example.com",
endsAt: "2000-02-01T00:03:42.000Z",
matchers: [
@@ -339,12 +355,11 @@ describe("<AlertAck />", () => {
alertStore.info.authentication.username = "wrong";
alertStore.settings.values.alertAcknowledgement.durationSeconds = 222;
alertStore.settings.values.alertAcknowledgement.author = "me";
alertStore.settings.values.alertAcknowledgement.commentPrefix = "FOO:";
alertStore.settings.values.alertAcknowledgement.comment = "FOO: bar";
silenceFormStore.data.setAuthor("bob@example.com");
await MountAndClick();
expect(JSON.parse((fetchMock.lastOptions() as any).body)).toEqual({
comment:
"FOO: This alert was acknowledged using karma on Tue, 01 Feb 2000 00:00:00 GMT",
comment: "FOO: bar",
createdBy: "bob@example.com",
endsAt: "2000-02-01T00:03:42.000Z",
matchers: [
@@ -358,12 +373,11 @@ describe("<AlertAck />", () => {
it("uses default author as fallback", async () => {
alertStore.settings.values.alertAcknowledgement.durationSeconds = 222;
alertStore.settings.values.alertAcknowledgement.author = "me";
alertStore.settings.values.alertAcknowledgement.commentPrefix = "FOO:";
alertStore.settings.values.alertAcknowledgement.comment = "FOO: bar";
silenceFormStore.data.setAuthor("");
await MountAndClick();
expect(JSON.parse((fetchMock.lastOptions() as any).body)).toEqual({
comment:
"FOO: This alert was acknowledged using karma on Tue, 01 Feb 2000 00:00:00 GMT",
comment: "FOO: bar",
createdBy: "me",
endsAt: "2000-02-01T00:03:42.000Z",
matchers: [
+4 -6
View File
@@ -74,19 +74,17 @@ const AlertAck: FC<{
const durationSeconds = toJS(
alertStore.settings.values.alertAcknowledgement.durationSeconds
);
const commentPrefix = toJS(
alertStore.settings.values.alertAcknowledgement.commentPrefix
);
const now = new Date();
const comment = toJS(
alertStore.settings.values.alertAcknowledgement.comment
).replace("%NOW%", now.toUTCString());
c.push({
payload: GenerateAlertmanagerSilenceData(
now,
addSeconds(now, durationSeconds),
MatchersFromGroup(group, [], group.alerts, true),
author,
`${
commentPrefix ? commentPrefix + " " : ""
}This alert was acknowledged using karma on ${now.toUTCString()}`
comment
),
clusterName: clusterName,
members: clusterMembers,
+1 -1
View File
@@ -182,7 +182,7 @@ export interface APISettingsT {
enabled: boolean;
durationSeconds: number;
author: string;
commentPrefix: string;
comment: string;
};
}
+1 -1
View File
@@ -413,7 +413,7 @@ class AlertStore {
enabled: false as boolean,
durationSeconds: 900,
author: "karma / author missing",
commentPrefix: "",
comment: "ACK! This alert was acknowledged using karma",
},
},
},
+1 -1
View File
@@ -73,7 +73,7 @@ const EmptyAPIResponse = (): APIAlertsResponseT => ({
enabled: false,
durationSeconds: 900,
author: "karma / author missing",
commentPrefix: "",
comment: "ACK! Mock comment",
},
staticColorLabels: ["job"],
annotationsDefaultHidden: false,