Merge ~ubuntu-docker-images/ubuntu-docker-images/+git/prometheus-alertmanager:update-20.04-use-snap into ~ubuntu-docker-images/ubuntu-docker-images/+git/prometheus-alertmanager:0.21-20.04
- Git
- lp:~ubuntu-docker-images/ubuntu-docker-images/+git/prometheus-alertmanager
- update-20.04-use-snap
- Merge into 0.21-20.04
Status: | Merged |
---|---|
Merged at revision: | d700675a3c1f0983a511287ed5b0178c0bee5b3c |
Proposed branch: | ~ubuntu-docker-images/ubuntu-docker-images/+git/prometheus-alertmanager:update-20.04-use-snap |
Merge into: | ~ubuntu-docker-images/ubuntu-docker-images/+git/prometheus-alertmanager:0.21-20.04 |
Diff against target: |
626670 lines (+214/-732) 8 files modified
.gitignore (+1/-4) Dockerfile (+32/-13) Makefile (+26/-56) README.md (+49/-366) data/prometheus-alertmanager.yaml (+40/-0) dev/null (+0/-293) examples/alertmanager-deployment.yml (+65/-0) promu/promu-0.5.0.linux-amd64/LICENSE (+1/-0) |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Bryce Harrington | Approve | ||
Lucas Kanashiro | Pending | ||
Canonical Server | Pending | ||
Review via email:
|
Commit message
Description of the change
Now that the prometheus-
This MP seems very big, but all it's doing is:
- Remove everything (except the "oci/" directory);
- Move everything inside "oci/" to the root dir;
- Update Dockerfile to use the snap (like we did for 21.04);
- Update the data YAML file to reflect the path change.
Tested by rebuilding and re-running the unit tests.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Sergio Durigan Junior (sergiodj) wrote : | # |
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Bryce Harrington (bryce) wrote : | # |
LGTM, +1
You're right this is a sizeable diff, but I focused on visual review of the Dockerfile, Makefile, README.md, and data/prometheus
I verified locally the branch's Dockerfile builds without issue for me.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Sergio Durigan Junior (sergiodj) wrote : | # |
Thanks, Bryce.
Preview Diff
1 | diff --git a/.circleci/config.yml b/.circleci/config.yml |
2 | deleted file mode 100644 |
3 | index 8a626c5..0000000 |
4 | --- a/.circleci/config.yml |
5 | +++ /dev/null |
6 | @@ -1,138 +0,0 @@ |
7 | ---- |
8 | -version: 2.1 |
9 | - |
10 | -orbs: |
11 | - prometheus: prometheus/prometheus@0.8.0 |
12 | - go: circleci/go@0.2.0 |
13 | - |
14 | -jobs: |
15 | - test_frontend: |
16 | - # We need to use a machine executor because the front-end validation runs |
17 | - # containers with mounted volumes which isn't supported with the docker |
18 | - # executor (even with setup_remote_docker). |
19 | - machine: true |
20 | - steps: |
21 | - - checkout |
22 | - - run: sudo service docker restart |
23 | - - run: |
24 | - name: Remove existing Go installation |
25 | - command: sudo rm -rf /usr/local/go |
26 | - # Whenever the Go version is updated here, .promu.yml should also be updated. |
27 | - - go/install: |
28 | - version: "1.14" |
29 | - - run: |
30 | - name: Remove generated code |
31 | - command: make clean |
32 | - - run: |
33 | - name: Generate front-end code |
34 | - command: make all |
35 | - working_directory: ~/project/ui/app |
36 | - environment: |
37 | - JUNIT_DIR: ~/test-results |
38 | - - run: |
39 | - name: Generate assets |
40 | - command: make assets |
41 | - - run: |
42 | - name: Generate API v2 code |
43 | - command: make apiv2 |
44 | - - run: git diff --exit-code |
45 | - - store_test_results: |
46 | - path: ~/test-results |
47 | - |
48 | - test: |
49 | - docker: |
50 | - # Whenever the Go version is updated here, .promu.yml should also be updated. |
51 | - - image: circleci/golang:1.14 |
52 | - # maildev containers are for running the email tests against a "real" SMTP server. |
53 | - # See notify/email_test.go for details. |
54 | - - image: djfarrelly/maildev@sha256:624e0ec781e11c3531da83d9448f5861f258ee008c1b2da63b3248bfd680acfa |
55 | - name: maildev-noauth |
56 | - entrypoint: bin/maildev |
57 | - command: |
58 | - - -v |
59 | - - image: djfarrelly/maildev@sha256:624e0ec781e11c3531da83d9448f5861f258ee008c1b2da63b3248bfd680acfa |
60 | - name: maildev-auth |
61 | - entrypoint: bin/maildev |
62 | - command: |
63 | - - -v |
64 | - - --incoming-user |
65 | - - user |
66 | - - --incoming-pass |
67 | - - pass |
68 | - |
69 | - environment: |
70 | - EMAIL_NO_AUTH_CONFIG: /tmp/smtp_no_auth.yml |
71 | - EMAIL_AUTH_CONFIG: /tmp/smtp_auth.yml |
72 | - |
73 | - steps: |
74 | - - prometheus/setup_environment |
75 | - - go/load-cache: |
76 | - key: v1-go-mod |
77 | - - run: |
78 | - command: | |
79 | - cat \<<EOF > $EMAIL_NO_AUTH_CONFIG |
80 | - smarthost: maildev-noauth:1025 |
81 | - server: http://maildev-noauth:1080/ |
82 | - EOF |
83 | - cat \<<EOF > $EMAIL_AUTH_CONFIG |
84 | - smarthost: maildev-auth:1025 |
85 | - server: http://maildev-auth:1080/ |
86 | - username: user |
87 | - password: pass |
88 | - EOF |
89 | - - run: |
90 | - command: make |
91 | - environment: |
92 | - # By default Go uses GOMAXPROCS but a Circle CI executor has many |
93 | - # cores (> 30) while the CPU and RAM resources are throttled. If we |
94 | - # don't limit this to the number of allocated cores, the job is |
95 | - # likely to get OOMed and killed. |
96 | - GOOPTS: "-p 2" |
97 | - - prometheus/check_proto: |
98 | - version: "3.11.4" |
99 | - - prometheus/store_artifact: |
100 | - file: alertmanager |
101 | - - prometheus/store_artifact: |
102 | - file: amtool |
103 | - - go/save-cache: |
104 | - key: v1-go-mod |
105 | - - store_test_results: |
106 | - path: test-results |
107 | - |
108 | -workflows: |
109 | - version: 2 |
110 | - alertmanager: |
111 | - jobs: |
112 | - - test_frontend: |
113 | - filters: |
114 | - tags: |
115 | - only: /.*/ |
116 | - - test: |
117 | - filters: |
118 | - tags: |
119 | - only: /.*/ |
120 | - - prometheus/build: |
121 | - name: build |
122 | - filters: |
123 | - tags: |
124 | - only: /.*/ |
125 | - - prometheus/publish_master: |
126 | - context: org-context |
127 | - requires: |
128 | - - test_frontend |
129 | - - test |
130 | - - build |
131 | - filters: |
132 | - branches: |
133 | - only: master |
134 | - - prometheus/publish_release: |
135 | - context: org-context |
136 | - requires: |
137 | - - test_frontend |
138 | - - test |
139 | - - build |
140 | - filters: |
141 | - tags: |
142 | - only: /^v[0-9]+(\.[0-9]+){2}(-.+|[^-.]*)$/ |
143 | - branches: |
144 | - ignore: /.*/ |
145 | diff --git a/.dockerignore b/.dockerignore |
146 | deleted file mode 100644 |
147 | index 6e6480b..0000000 |
148 | --- a/.dockerignore |
149 | +++ /dev/null |
150 | @@ -1,8 +0,0 @@ |
151 | -.build/ |
152 | -.tarballs/ |
153 | - |
154 | -!.build/linux-amd64/ |
155 | -!.build/linux-armv7/ |
156 | -!.build/linux-arm64/ |
157 | -!.build/linux-ppc64le/ |
158 | -!.build/linux-s390x/ |
159 | diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md |
160 | deleted file mode 100644 |
161 | index ce79ffa..0000000 |
162 | --- a/.github/ISSUE_TEMPLATE.md |
163 | +++ /dev/null |
164 | @@ -1,47 +0,0 @@ |
165 | -<!-- |
166 | - |
167 | - Please do *NOT* ask usage questions in Github issues. |
168 | - |
169 | - If your issue is not a feature request or bug report use: |
170 | - https://groups.google.com/forum/#!forum/prometheus-users. If |
171 | - you are unsure whether you hit a bug, search and ask in the |
172 | - mailing list first. |
173 | - |
174 | - You can find more information at: https://prometheus.io/community/ |
175 | - |
176 | ---> |
177 | - |
178 | -**What did you do?** |
179 | - |
180 | -**What did you expect to see?** |
181 | - |
182 | -**What did you see instead? Under which circumstances?** |
183 | - |
184 | -**Environment** |
185 | - |
186 | -* System information: |
187 | - |
188 | - insert output of `uname -srm` here |
189 | - |
190 | -* Alertmanager version: |
191 | - |
192 | - insert output of `alertmanager --version` here |
193 | - |
194 | -* Prometheus version: |
195 | - |
196 | - insert output of `prometheus --version` here (if relevant to the issue) |
197 | - |
198 | -* Alertmanager configuration file: |
199 | -``` |
200 | -insert configuration here |
201 | -``` |
202 | - |
203 | -* Prometheus configuration file: |
204 | -``` |
205 | -insert configuration here (if relevant to the issue) |
206 | -``` |
207 | - |
208 | -* Logs: |
209 | -``` |
210 | -insert Prometheus and Alertmanager logs relevant to the issue here |
211 | -``` |
212 | diff --git a/.github/stale.yml b/.github/stale.yml |
213 | deleted file mode 100644 |
214 | index 66a72af..0000000 |
215 | --- a/.github/stale.yml |
216 | +++ /dev/null |
217 | @@ -1,56 +0,0 @@ |
218 | -# Configuration for probot-stale - https://github.com/probot/stale |
219 | - |
220 | -# Number of days of inactivity before an Issue or Pull Request becomes stale |
221 | -daysUntilStale: 60 |
222 | - |
223 | -# Number of days of inactivity before an Issue or Pull Request with the stale label is closed. |
224 | -# Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale. |
225 | -daysUntilClose: false |
226 | - |
227 | -# Only issues or pull requests with all of these labels are check if stale. Defaults to `[]` (disabled) |
228 | -onlyLabels: [] |
229 | - |
230 | -# Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable |
231 | -exemptLabels: |
232 | - - keepalive |
233 | - |
234 | -# Set to true to ignore issues in a project (defaults to false) |
235 | -exemptProjects: false |
236 | - |
237 | -# Set to true to ignore issues in a milestone (defaults to false) |
238 | -exemptMilestones: false |
239 | - |
240 | -# Set to true to ignore issues with an assignee (defaults to false) |
241 | -exemptAssignees: false |
242 | - |
243 | -# Label to use when marking as stale |
244 | -staleLabel: stale |
245 | - |
246 | -# Comment to post when marking as stale. Set to `false` to disable |
247 | -markComment: false |
248 | - |
249 | -# Comment to post when removing the stale label. |
250 | -# unmarkComment: > |
251 | -# Your comment here. |
252 | - |
253 | -# Comment to post when closing a stale Issue or Pull Request. |
254 | -# closeComment: > |
255 | -# Your comment here. |
256 | - |
257 | -# Limit the number of actions per hour, from 1-30. Default is 30 |
258 | -limitPerRun: 30 |
259 | - |
260 | -# Limit to only `issues` or `pulls` |
261 | -only: pulls |
262 | - |
263 | -# Optionally, specify configuration settings that are specific to just 'issues' or 'pulls': |
264 | -# pulls: |
265 | -# daysUntilStale: 30 |
266 | -# markComment: > |
267 | -# This pull request has been automatically marked as stale because it has not had |
268 | -# recent activity. It will be closed if no further activity occurs. Thank you |
269 | -# for your contributions. |
270 | - |
271 | -# issues: |
272 | -# exemptLabels: |
273 | -# - confirmed |
274 | diff --git a/.gitignore b/.gitignore |
275 | index 205826a..0350652 100644 |
276 | --- a/.gitignore |
277 | +++ b/.gitignore |
278 | @@ -1,4 +1 @@ |
279 | -/*.snap |
280 | -/parts/ |
281 | -/prime/ |
282 | -/stage/ |
283 | +templates/ |
284 | diff --git a/.golangci.yml b/.golangci.yml |
285 | deleted file mode 100644 |
286 | index 1a05236..0000000 |
287 | --- a/.golangci.yml |
288 | +++ /dev/null |
289 | @@ -1,13 +0,0 @@ |
290 | -run: |
291 | - modules-download-mode: vendor |
292 | - deadline: 5m |
293 | - |
294 | -issues: |
295 | - exclude-rules: |
296 | - - path: _test.go |
297 | - linters: |
298 | - - errcheck |
299 | - |
300 | -linters-settings: |
301 | - errcheck: |
302 | - exclude: scripts/errcheck_excludes.txt |
303 | diff --git a/.promu.yml b/.promu.yml |
304 | deleted file mode 100644 |
305 | index 1c417c7..0000000 |
306 | --- a/.promu.yml |
307 | +++ /dev/null |
308 | @@ -1,48 +0,0 @@ |
309 | -go: |
310 | - # Whenever the Go version is updated here, .travis.yml and |
311 | - # .circle/config.yml should also be updated. |
312 | - version: 1.14 |
313 | -repository: |
314 | - path: github.com/prometheus/alertmanager |
315 | -build: |
316 | - binaries: |
317 | - - name: alertmanager |
318 | - path: ./cmd/alertmanager |
319 | - - name: amtool |
320 | - path: ./cmd/amtool |
321 | - flags: -mod vendor -a -tags netgo |
322 | - ldflags: | |
323 | - -X github.com/prometheus/common/version.Version={{.Version}} |
324 | - -X github.com/prometheus/common/version.Revision={{.Revision}} |
325 | - -X github.com/prometheus/common/version.Branch={{.Branch}} |
326 | - -X github.com/prometheus/common/version.BuildUser={{user}}@{{host}} |
327 | - -X github.com/prometheus/common/version.BuildDate={{date "20060102-15:04:05"}} |
328 | -tarball: |
329 | - files: |
330 | - - examples/ha/alertmanager.yml |
331 | - - LICENSE |
332 | - - NOTICE |
333 | -crossbuild: |
334 | - platforms: |
335 | - - linux/amd64 |
336 | - - linux/386 |
337 | - - darwin/amd64 |
338 | - - darwin/386 |
339 | - - windows/amd64 |
340 | - - windows/386 |
341 | - - freebsd/amd64 |
342 | - - freebsd/386 |
343 | - - openbsd/amd64 |
344 | - - openbsd/386 |
345 | - - netbsd/amd64 |
346 | - - netbsd/386 |
347 | - - dragonfly/amd64 |
348 | - - linux/arm |
349 | - - linux/arm64 |
350 | - - freebsd/arm |
351 | - - netbsd/arm |
352 | - - linux/ppc64 |
353 | - - linux/ppc64le |
354 | - - linux/mips64 |
355 | - - linux/mips64le |
356 | - - linux/s390x |
357 | diff --git a/CHANGELOG.md b/CHANGELOG.md |
358 | deleted file mode 100644 |
359 | index 93dc0af..0000000 |
360 | --- a/CHANGELOG.md |
361 | +++ /dev/null |
362 | @@ -1,564 +0,0 @@ |
363 | -## 0.21.0 / 2020-06-16 |
364 | - |
365 | -This release removes the HipChat integration as it is discontinued by Atlassian on June 30th 2020. |
366 | - |
367 | -* [CHANGE] [HipChat] Remove HipChat integration as it is end-of-life. #2282 |
368 | -* [CHANGE] [amtool] Remove default assignment of environment variables. #2161 |
369 | -* [CHANGE] [PagerDuty] Enforce 512KB event size limit. #2225 |
370 | -* [ENHANCEMENT] [amtool] Add `cluster` command to show cluster and peer statuses. #2256 |
371 | -* [ENHANCEMENT] Add redirection from `/` to the routes prefix when it isn't empty. #2235 |
372 | -* [ENHANCEMENT] [Webhook] Add `max_alerts` option to limit the number of alerts included in the payload. #2274 |
373 | -* [ENHANCEMENT] Improve logs for API v2, notifications and clustering. #2177 #2188 #2260 #2261 #2273 |
374 | -* [BUGFIX] Fix child routes not inheriting their parent route's grouping when `group_by: [...]`. #2154 |
375 | -* [BUGFIX] [UI] Fix the receiver selector in the Alerts page when the receiver name contains regular expression metacharacters such as `+`. #2090 |
376 | -* [BUGFIX] Fix error message about start and end time validation. #2173 |
377 | -* [BUGFIX] Fix a potential race condition in dispatcher. #2208 |
378 | -* [BUGFIX] [API v2] Return an empty array of peers when the clustering is disabled. #2203 |
379 | -* [BUGFIX] Fix the registration of `alertmanager_dispatcher_aggregation_groups` and `alertmanager_dispatcher_alert_processing_duration_seconds` metrics. #2200 |
380 | -* [BUGFIX] Always retry notifications with back-off. #2290 |
381 | - |
382 | -## 0.20.0 / 2019-12-11 |
383 | - |
384 | -* [CHANGE] Check that at least one silence matcher matches a non-empty string. #2081 |
385 | -* [ENHANCEMENT] [pagerduty] Check that PagerDuty keys aren't empty. #2085 |
386 | -* [ENHANCEMENT] [template] Add the `stringSlice` function. #2101 |
387 | -* [ENHANCEMENT] Add `alertmanager_dispatcher_aggregation_groups` and `alertmanager_dispatcher_alert_processing_duration_seconds` metrics. #2113 |
388 | -* [ENHANCEMENT] Log unused receivers. #2114 |
389 | -* [ENHANCEMENT] Add `alertmanager_receivers` metric. #2114 |
390 | -* [ENHANCEMENT] Add `alertmanager_integrations` metric. #2117 |
391 | -* [ENHANCEMENT] [email] Add Message-Id Header to outgoing emails. #2057 |
392 | -* [BUGFIX] Don't garbage-collect alerts from the store. #2040 |
393 | -* [BUGFIX] [ui] Disable the grammarly plugin on all textareas. #2061 |
394 | -* [BUGFIX] [config] Forbid nil regexp matchers. #2083 |
395 | -* [BUGFIX] [ui] Fix Silences UI when several filters are applied. #2075 |
396 | - |
397 | -Contributors: |
398 | - |
399 | -* @CharlesJUDITH |
400 | -* @NotAFile |
401 | -* @Pger-Y |
402 | -* @TheMeier |
403 | -* @johncming |
404 | -* @n33pm |
405 | -* @ntk148v |
406 | -* @oddlittlebird |
407 | -* @perlun |
408 | -* @qoops-1 |
409 | -* @roidelapluie |
410 | -* @simonpasquier |
411 | -* @stephenreddek |
412 | -* @sylr |
413 | -* @vrischmann |
414 | - |
415 | -## 0.19.0 / 2019-09-03 |
416 | - |
417 | -* [CHANGE] Reject invalid external URLs at startup. #1960 |
418 | -* [CHANGE] Add Fingerprint to template data. #1945 |
419 | -* [CHANGE] Check Smarthost validity at config loading. #1957 |
420 | -* [ENHANCEMENT] Improve error messages for email receiver. #1953 |
421 | -* [ENHANCEMENT] Log error messages from OpsGenie API. #1965 |
422 | -* [ENHANCEMENT] Add the ability to configure Slack markdown field. #1967 |
423 | -* [ENHANCEMENT] Log warning when repeat_interval > retention. #1993 |
424 | -* [ENHANCEMENT] Add `alertmanager_cluster_enabled` metric. #1973 |
425 | -* [ENHANCEMENT] [ui] Recreate silence with previous comment. #1927 |
426 | -* [BUGFIX] [ui] Fix /api/v2/alerts/groups endpoint with similar alert groups. #1964 |
427 | -* [BUGFIX] Allow slashes in receivers. #2011 |
428 | -* [BUGFIX] [ui] Fix expand/collapse button with identical alert groups. #2012 |
429 | - |
430 | -## 0.18.0 / 2019-07-08 |
431 | - |
432 | -* [CHANGE] Remove quantile labels from Summary metrics. #1921 |
433 | -* [CHANGE] [OpsGenie] Move from the deprecated `teams` field in the configuration to `responders`. #1863 |
434 | -* [CHANGE] [ui] Collapse alert groups on the initial view. #1876 |
435 | -* [CHANGE] [Wechat] Set the default API secret to blank. #1888 |
436 | -* [CHANGE/BUGFIX] [PagerDuty] Fix embedding of images, the `text` field in the configuration has been renamed to `href`. #1931 |
437 | -* [ENHANCEMENT] Use persistent HTTP clients. #1904 |
438 | -* [ENHANCEMENT] Add `alertmanager_cluster_alive_messages_total`, `alertmanager_cluster_peer_info` and `alertmanager_cluster_pings_seconds` metrics. #1941 |
439 | -* [ENHANCEMENT] [api] Add missing metrics for API v2. #1902 |
440 | -* [ENHANCEMENT] [Slack] Log error message on retry errors. #1655 |
441 | -* [ENHANCEMENT] [ui] Allow to create silences from the alerts filter bar. #1911 |
442 | -* [ENHANCEMENT] [ui] Enable auto resize the textarea fields. #1893 |
443 | -* [BUGFIX] [amtool] Use scheme, authentication and base path from the URL if present. #1892 #1940 |
444 | -* [BUGFIX] [amtool] Support filtering alerts by receiver. #1915 |
445 | -* [BUGFIX] [api] Fix /api/v2/alerts with multiple receivers. #1948 |
446 | -* [BUGFIX] [PagerDuty] Truncate description to 1024 chars for PagerDuty v1. #1922 |
447 | -* [BUGFIX] [ui] Add filtering based off of "active" query param. #1879 |
448 | - |
449 | - |
450 | -## 0.17.0 / 2019-05-02 |
451 | - |
452 | -This release includes changes to amtool which are not fully backwards |
453 | -compatible with the previous amtool version (#1798) related to backup and |
454 | -import of silences. If a backup of silences is created using a previous |
455 | -version of amtool (v0.16.1 or earlier), it is possible that not all silences |
456 | -can be correctly imported using a later version of amtool. |
457 | - |
458 | -Additionally, the groups endpoint that was dropped from api v1 has been added |
459 | -to api v2. The default for viewing alerts in the UI now consumes from this |
460 | -endpoint and displays alerts grouped according to the groups defined in the |
461 | -running configuration. Custom grouping is still supported. |
462 | - |
463 | -This release has added two new flags that may need to be tweaked. For people |
464 | -running with a lot of concurrent requests, consider increasing the value of |
465 | -`--web.get-concurrency`. An increase in 503 errors indicates that the request |
466 | -rate is exceeding the number of currently available workers. The other new |
467 | -flag, --web.timeout, limits the time a request is allowed to run. The default |
468 | -behavior is to not use a timeout. |
469 | - |
470 | -* [CHANGE] Modify the self-inhibition prevention semantics (#1873) |
471 | -* [CHANGE] Make api/v2/status.cluster.{name,peers} properties optional for Alertmanager with disabled clustering (#1728) |
472 | -* [FEATURE] Add groups endpoint to v2 api (#1791) |
473 | -* [FEATURE] Optional timeout for HTTP requests (#1743) |
474 | -* [ENHANCEMENT] Set HTTP headers to prevent asset caching (#1817) |
475 | -* [ENHANCEMENT] API returns current silenced/inhibited state of alerts (#1733) |
476 | -* [ENHANCEMENT] Configurable concurrency limit for GET requests (#1743) |
477 | -* [ENHANCEMENT] Pushover notifier: support HTML, URL title and custom sounds (#1634) |
478 | -* [ENHANCEMENT] Support adding custom fields to VictorOps notifications (#1420) |
479 | -* [ENHANCEMENT] Migrate amtool CLI to API v2 (#1798) |
480 | -* [ENHANCEMENT][ui] Default alert list view grouped by configured alert groups (#1864) |
481 | -* [ENHANCEMENT][ui] Remove superfluous inhibited/silenced text, show inhibited status (#1698, #1862) |
482 | -* [ENHANCEMENT][ui] Silence preview now shows already-muted alerts (#1776) |
483 | -* [ENHANCEMENT][ui] Sort silences from api/v2 similarly to api/v1 (#1786) |
484 | -* [BUGFIX] Trim PagerDuty message summary to 1024 chars (#1701) |
485 | -* [BUGFIX] Add fix for race causing alerts to be dropped (#1843) |
486 | -* [BUGFIX][ui] Correctly construct filter query string for api (#1869) |
487 | -* [BUGFIX][ui] Do not display GroupByAll and GroupBy in marshaled config (#1665) |
488 | -* [BUGFIX][ui] Respect regex setting when creating silences (#1697) |
489 | - |
490 | -## 0.16.2 / 2019-04-03 |
491 | - |
492 | -Updating to v0.16.2 is recommended for all users using the Slack, Pagerduty, |
493 | -Hipchat, Wechat, VictorOps and Pushover notifier, as connection errors could |
494 | -leak secrets embedded in the notifier's URL to stdout. |
495 | - |
496 | -* [BUGFIX] Redact notifier URL from logs to not leak secrets embedded in the URL (#1822, #1825) |
497 | -* [BUGFIX] Allow sending of unauthenticated SMTP requests when `smtp_auth_username` is not supplied (#1739) |
498 | - |
499 | -## 0.16.1 / 2019-01-31 |
500 | - |
501 | -* [BUGFIX] Do not populate cluster info if clustering is disabled in API v2 (#1726) |
502 | - |
503 | -## 0.16.0 / 2019-01-17 |
504 | - |
505 | -This release introduces a new API v2, fully generated via the OpenAPI project |
506 | -[1]. At the same time with this release the previous API v1 is being |
507 | -deprecated. API v1 will be removed with Alertmanager release v0.18.0. |
508 | - |
509 | -* [CHANGE] Deprecate API v1 |
510 | -* [CHANGE] Remove `api/v1/alerts/groups` GET endpoint (#1508 & #1525) |
511 | -* [CHANGE] Revert Alertmanager working directory changes in Docker image back to `/alertmanager` (#1435) |
512 | -* [CHANGE] Using the recommended label syntax for maintainer in Dockerfile (#1533) |
513 | -* [CHANGE] Change `alertmanager_notifications_total` to count attempted notifications, not only successful ones (#1578) |
514 | -* [CHANGE] Run as nobody inside container (#1586) |
515 | -* [CHANGE] Support `w` for weeks when creating silences, remove `y` for year (#1620) |
516 | -* [FEATURE] Introduce OpenAPI generated API v2 (#1352) |
517 | -* [FEATURE] Lookup parts in strings using regexp.MatchString in templates (#1452) |
518 | -* [FEATURE] Support image/thumb url in attachment in Slack notifier (#1506) |
519 | -* [FEATURE] Support custom TLS certificates for the email notifier (#1528) |
520 | -* [FEATURE] Add support for images and links in the PagerDuty notification config (#1559) |
521 | -* [FEATURE] Add support for grouping by all labels (#1588) |
522 | -* [FEATURE] [amtool] Add timeout support to amtool commands (#1471) |
523 | -* [FEATURE] [amtool] Added `config routes` tools for visualization and testing routes (#1511) |
524 | -* [FEATURE] [amtool] Support adding alerts using amtool (#1461) |
525 | -* [ENHANCEMENT] Add support for --log.format (#1658) |
526 | -* [ENHANCEMENT] Add CORS support to API v2 (#1667) |
527 | -* [ENHANCEMENT] Support HTML, URL title and custom sounds for Pushover (#1634) |
528 | -* [ENHANCEMENT] Update Alert compact view (#1698) |
529 | -* [ENHANCEMENT] Support adding custom fields to VictorOps notifications (#1420) |
530 | -* [ENHANCEMENT] Add help link in UI to Alertmanager documentation (#1522) |
531 | -* [ENHANCEMENT] Enforce HTTP or HTTPS URLs in Alertmanager config (#1567) |
532 | -* [ENHANCEMENT] Make OpsGenie API Key a templated string (#1594) |
533 | -* [ENHANCEMENT] Add name, value and SlackConfirmationField to action in Slack notifier (#1557) |
534 | -* [ENHANCEMENT] Show more alert information on silence form and silence view pages (#1601) |
535 | -* [ENHANCEMENT] Add cluster peers DNS refresh job (#1428) |
536 | -* [BUGFIX] Fix unmarshaling of secret URLs in config (#1663) |
537 | -* [BUGFIX] Do not write groupbyall and groupby when marshaling config (#1665) |
538 | -* [BUGFIX] Make a copy of firing alerts with EndsAt=0 when flushing (#1686) |
539 | -* [BUGFIX] Respect regex matchers when recreating silences in UI (#1697) |
540 | -* [BUGFIX] Change DefaultGlobalConfig to a function in Alertmanager configuration (#1656) |
541 | -* [BUGFIX] Fix email template typo in alert-warning style (#1421) |
542 | -* [BUGFIX] Fix silence redirect on silence creation UI page (#1548) |
543 | -* [BUGFIX] Add missing `callback_id` parameter in Slack notifier (#1592) |
544 | -* [BUGFIX] Throw error if no auth mechanism matches in email notifier (#1608) |
545 | -* [BUGFIX] Use quoted-printable transfer encoding for the email notifier (#1609) |
546 | -* [BUGFIX] Do not merge expired gossip messages (#1631) |
547 | -* [BUGFIX] Fix "PLAIN" auth during notification via smtp-over-tls on port 465 (#1591) |
548 | -* [BUGFIX] [amtool] Support for assuming first label is alertname in silence add and query (#1693) |
549 | -* [BUGFIX] [amtool] Support assuming first label is alertname in alert query with matchers (#1575) |
550 | -* [BUGFIX] [amtool] Fix config path check in amtool (#1538) |
551 | -* [BUGFIX] [amtool] Fix rfc3339 example texts (#1526) |
552 | -* [BUGFIX] [amtool] Fixed issue with loading path of a default configs (#1529) |
553 | - |
554 | -[1] https://github.com/prometheus/alertmanager#api |
555 | - |
556 | -## 0.15.3 / 2018-11-09 |
557 | - |
558 | -* [BUGFIX] Fix alert merging supporting both empty and set EndsAt property for firing alerts send by Prometheus (#1611) |
559 | - |
560 | -## 0.15.2 / 2018-08-14 |
561 | - |
562 | -* [ENHANCEMENT] [amtool] Add support for stdin to check-config (#1431) |
563 | -* [ENHANCEMENT] Log PagerDuty v1 response on BadRequest (#1481) |
564 | -* [BUGFIX] Correctly encode query strings in notifiers (#1516) |
565 | -* [BUGFIX] Add cache control headers to the API responses to avoid IE caching (#1500) |
566 | -* [BUGFIX] Avoid listener blocking on unsubscribe (#1482) |
567 | -* [BUGFIX] Fix a bunch of unhandled errors (#1501) |
568 | -* [BUGFIX] Update PagerDuty API V2 to send full details on resolve (#1483) |
569 | -* [BUGFIX] Validate URLs at config load time (#1468) |
570 | -* [BUGFIX] Fix Settle() interval (#1478) |
571 | -* [BUGFIX] Fix email to be green if only none firing (#1475) |
572 | -* [BUGFIX] Handle errors in notify (#1474) |
573 | -* [BUGFIX] Fix templating of hipchat room id (#1463) |
574 | - |
575 | -## 0.15.1 / 2018-07-10 |
576 | - |
577 | -* [BUGFIX] Fix email template typo in alert-warning style (#1421) |
578 | -* [BUGFIX] Fix regression in Pager Duty config (#1455) |
579 | -* [BUGFIX] Catch templating errors in Wechat Notify (#1436) |
580 | -* [BUGFIX] Fail when no private address can be found for cluster (#1437) |
581 | -* [BUGFIX] Make sure we don't miss the first pushPull when joining cluster (#1456) |
582 | -* [BUGFIX] Fix concurrent read and write group error in dispatch (#1447) |
583 | - |
584 | -## 0.15.0 / 2018-06-22 |
585 | - |
586 | -* [CHANGE] [amtool] Update silence add and update flags (#1298) |
587 | -* [CHANGE] Replace deprecated InstrumentHandler() (#1302) |
588 | -* [CHANGE] Validate Slack field config and only allow the necessary input (#1334) |
589 | -* [CHANGE] Remove legacy alert ingest endpoint (#1362) |
590 | -* [CHANGE] Move to memberlist as underlying gossip protocol including cluster flag changes from --mesh.xxx to --cluster.xxx (#1232) |
591 | -* [CHANGE] Move Alertmanager working directory in Docker image to /etc/alertmanager (#1313) |
592 | -* [BUGFIX/CHANGE] The default group by is no labels. (#1287) |
593 | -* [FEATURE] [amtool] Filter alerts by receiver (#1402) |
594 | -* [FEATURE] Wait for mesh to settle before sending alerts (#1209) |
595 | -* [FEATURE] [amtool] Support basic auth in alertmanager url (#1279) |
596 | -* [FEATURE] Make HTTP clients used for integrations configurable |
597 | -* [ENHANCEMENT] Support receiving alerts with end time and zero start time |
598 | -* [ENHANCEMENT] Sort dispatched alerts by job+instance (#1234) |
599 | -* [ENHANCEMENT] Support alert query filters `active` and `unprocessed` (#1366) |
600 | -* [ENHANCEMENT] [amtool] Expose alert query flags --active and --unprocessed (#1370) |
601 | -* [ENHANCEMENT] Add Slack actions to notifications (#1355) |
602 | -* [BUGFIX] Register nflog snapShotSize metric |
603 | -* [BUGFIX] Sort alerts in correct order before flushing to notifiers (#1349) |
604 | -* [BUGFIX] Don't reset initial wait timer if flush is in-progress (#1301) |
605 | -* [BUGFIX] Fix resolved alerts still inhibiting (#1331) |
606 | -* [BUGFIX] Template wechat config fields (#1356) |
607 | -* [BUGFIX] Notify resolved alerts properly (#1408) |
608 | -* [BUGFIX] Fix parsing for label values with commas (#1395) |
609 | -* [BUGFIX] Hide sensitive Wechat configuration (#1253) |
610 | -* [BUGFIX] Prepopulate matchers when recreating a silence (#1270) |
611 | -* [BUGFIX] Fix wechat panic (#1293) |
612 | -* [BUGFIX] Allow empty matchers in silences/filtering (#1289) |
613 | -* [BUGFIX] Properly configure HTTP client for Wechat integration |
614 | - |
615 | -## 0.14.0 / 2018-02-12 |
616 | - |
617 | -* [ENHANCEMENT] [amtool] Silence update support dwy suffixes to expire flag (#1197) |
618 | -* [ENHANCEMENT] Allow templating PagerDuty receiver severity (#1214) |
619 | -* [ENHANCEMENT] Include receiver name in failed notifications log messages (#1207) |
620 | -* [ENHANCEMENT] Allow global opsgenie api key (#1208) |
621 | -* [ENHANCEMENT] Add mesh metrics (#1225) |
622 | -* [ENHANCEMENT] Add Class field to PagerDuty; add templating to PagerDuty-CEF fields (#1231) |
623 | -* [BUGFIX] Don't notify of resolved alerts if none were reported firing (#1198) |
624 | -* [BUGFIX] Notify only when new firing alerts are added (#1205) |
625 | -* [BUGFIX] [mesh] Fix pending connections never set to established (#1204) |
626 | -* [BUGFIX] Allow OpsGenie notifier to have empty team fields (#1224) |
627 | -* [BUGFIX] Don't count alerts with EndTime in the future as resolved (#1233) |
628 | -* [BUGFIX] Speed up re-rendering of Silence UI (#1235) |
629 | -* [BUGFIX] Forbid 0 value for group_interval and repeat_interval (#1230) |
630 | -* [BUGFIX] Fix WeChat agentid issue (#1229) |
631 | - |
632 | -## 0.13.0 / 2018-01-12 |
633 | - |
634 | -* [CHANGE] Switch cmd/alertmanager to kingpin (#974) |
635 | -* [CHANGE] [amtool] Switch amtool to kingpin (#976) |
636 | -* [CHANGE] [amtool] silence query: --expired flag only shows expired silences (#1190) |
637 | -* [CHANGE] Return config reload result from reload endpoint (#1180) |
638 | -* [FEATURE] UI silence form is populated from location bar (#1148) |
639 | -* [FEATURE] Add /-/healthy endpoint (#1159) |
640 | -* [ENHANCEMENT] Instrument and log snapshot sizes on maintenance (#1155) |
641 | -* [ENHANCEMENT] Make alertGC interval configurable (#1151) |
642 | -* [ENHANCEMENT] Display mesh connections in the Status page (#1164) |
643 | -* [BUGFIX] Template service keys for pagerduty notifier (#1182) |
644 | -* [BUGFIX] Fix expire buttons on the silences page (#1171) |
645 | -* [BUGFIX] Fix JavaScript error in MSIE due to endswith() usage (#1172) |
646 | -* [BUGFIX] Correctly format UI error output (#1167) |
647 | - |
648 | -## 0.12.0 / 2017-12-15 |
649 | - |
650 | -* [FEATURE] package amtool in docker container (#1127) |
651 | -* [FEATURE] Add notify support for Chinese User wechat (#1059) |
652 | -* [FEATURE] [amtool] Add a new `silence import` command (#1082) |
653 | -* [FEATURE] [amtool] Add new command to update silence (#1123) |
654 | -* [FEATURE] [amtool] Add ability to query for silences that will expire soon (#1120) |
655 | -* [ENHANCEMENT] Template source field in PagerDuty alert payload (#1117) |
656 | -* [ENHANCEMENT] Add footer field for slack messages (#1141) |
657 | -* [ENHANCEMENT] Add Slack additional "fields" to notifications (#1135) |
658 | -* [ENHANCEMENT] Adding check for webhook's URL formatting (#1129) |
659 | -* [ENHANCEMENT] Let the browser remember the creator of a silence (#1112) |
660 | -* [BUGFIX] Fix race in stopping inhibitor (#1118) |
661 | -* [BUGFIX] Fix browser UI when entering negative duration (#1132) |
662 | - |
663 | -## 0.11.0 / 2017-11-16 |
664 | - |
665 | -* [CHANGE] Make silence negative filtering consistent with alert filtering (#1095) |
666 | -* [CHANGE] Change HipChat and OpsGenie api config names (#1087) |
667 | -* [ENHANCEMENT] amtool: Allow 'd', 'w', 'y' time suffixes when creating silence (#1091) |
668 | -* [ENHANCEMENT] Support OpsGenie Priority field (#1094) |
669 | -* [BUGFIX] Fix UI when no silences are present (#1090) |
670 | -* [BUGFIX] Fix OpsGenie Teams field (#1101) |
671 | -* [BUGFIX] Fix OpsGenie Tags field (#1108) |
672 | - |
673 | -## 0.10.0 / 2017-11-09 |
674 | - |
675 | -* [CHANGE] Prevent inhibiting alerts in the source of the inhibition (#1017) |
676 | -* [ENHANCEMENT] Improve amtool check-config use and description text (#1016) |
677 | -* [ENHANCEMENT] Add metrics about current silences and alerts (#998) |
678 | -* [ENHANCEMENT] Sorted silences based on current status (#1015) |
679 | -* [ENHANCEMENT] Add metric of alertmanager position in mesh (#1024) |
680 | -* [ENHANCEMENT] Initialise notifications_total and notifications_failed_total (#1011) |
681 | -* [ENHANCEMENT] Allow selectable matchers on silence view (#1030) |
682 | -* [ENHANCEMENT] Allow template in victorops message_type field (#1038) |
683 | -* [ENHANCEMENT] Optionally hide inhibited alerts in API response (#1039) |
684 | -* [ENHANCEMENT] Toggle silenced and inhibited alerts in UI (#1049) |
685 | -* [ENHANCEMENT] Fix pushover limits (title, message, url) (#1055) |
686 | -* [ENHANCEMENT] Add limit to OpsGenie message (#1045) |
687 | -* [ENHANCEMENT] Upgrade OpsGenie notifier to v2 API. (#1061) |
688 | -* [ENHANCEMENT] Allow template in victorops routing_key field (#1083) |
689 | -* [ENHANCEMENT] Add support for PagerDuty API v2 (#1054) |
690 | -* [BUGFIX] Fix inhibit race (#1032) |
691 | -* [BUGFIX] Fix segfault on amtool (#1031) |
692 | -* [BUGFIX] Remove .WasInhibited and .WasSilenced fields of Alert type (#1026) |
693 | -* [BUGFIX] nflog: Fix Log() crash when gossip is nil (#1064) |
694 | -* [BUGFIX] Fix notifications for flapping alerts (#1071) |
695 | -* [BUGFIX] Fix shutdown crash with nil mesh router (#1077) |
696 | -* [BUGFIX] Fix negative matchers filtering (#1077) |
697 | - |
698 | -## 0.9.1 / 2017-09-29 |
699 | -* [BUGFIX] Fix -web.external-url regression in ui (#1008) |
700 | -* [BUGFIX] Fix multipart email implementation (#1009) |
701 | - |
702 | -## 0.9.0 / 2017-09-28 |
703 | -* [ENHANCEMENT] Add current time to webhook message (#909) |
704 | -* [ENHANCEMENT] Add link_names to slack notifier (#912) |
705 | -* [ENHANCEMENT] Make ui labels selectable/highlightable (#932) |
706 | -* [ENHANCEMENT] Make links in ui annotations selectable (#946) |
707 | -* [ENHANCEMENT] Expose the alert's "fingerprint" (unique identifier) through API (#786) |
708 | -* [ENHANCEMENT] Add README information for amtool (#939) |
709 | -* [ENHANCEMENT] Use user-set logging option consistently throughout alertmanager (#968) |
710 | -* [ENHANCEMENT] Sort alerts returned from API by their fingerprint (#969) |
711 | -* [ENHANCEMENT] Add edit/delete silence buttons on silence page view (#970) |
712 | -* [ENHANCEMENT] Add check-config subcommand to amtool (#978) |
713 | -* [ENHANCEMENT] Add email notification text content support (#934) |
714 | -* [ENHANCEMENT] Support passing binary name to make build target (#990) |
715 | -* [ENHANCEMENT] Show total no. of silenced alerts in preview (#994) |
716 | -* [ENHANCEMENT] Added confirmation dialog when expiring silences (#993) |
717 | -* [BUGFIX] Fix crash when no mesh router is configured (#919) |
718 | -* [BUGFIX] Render status page without mesh (#920) |
719 | -* [BUGFIX] Exit amtool subcommands with non-zero error code (#938) |
720 | -* [BUGFIX] Change mktemp invocation in makefile to work for macOS (#971) |
721 | -* [BUGFIX] Add a mutex to silences.go:gossipData (#984) |
722 | -* [BUGFIX] silences: avoid deadlock (#995) |
723 | -* [BUGFIX] Ignore expired silences OnGossip (#999) |
724 | - |
725 | -## 0.8.0 / 2017-07-20 |
726 | - |
727 | -* [FEATURE] Add ability to filter alerts by receiver in the UI (#890) |
728 | -* [FEATURE] Add User-Agent for webhook requests (#893) |
729 | -* [ENHANCEMENT] Add possibility to have a global victorops api_key (#897) |
730 | -* [ENHANCEMENT] Add EntityDisplayName and improve StateMessage for Victorops |
731 | - (#769) |
732 | -* [ENHANCEMENT] Omit empty config fields and show regex upon re-marshaling to |
733 | - elide secrets (#864) |
734 | -* [ENHANCEMENT] Parse API error messages in UI (#866) |
735 | -* [ENHANCEMENT] Enable sending mail via smtp port 465 (#704) |
736 | -* [BUGFIX] Prevent duplicate notifications by sorting matchers (#882) |
737 | -* [BUGFIX] Remove timeout for UI requests (#890) |
738 | -* [BUGFIX] Update config file location of CLI in flag usage text (#895) |
739 | - |
740 | -## 0.7.1 / 2017-06-09 |
741 | - |
742 | -* [BUGFIX] Fix filtering by label on Alert list and Silence list page |
743 | - |
744 | -## 0.7.0 / 2017-06-08 |
745 | - |
746 | -* [CHANGE] Rewrite UI from scratch improving UX |
747 | -* [CHANGE] Rename `config` to `configYAML` on `api/v1/status` |
748 | -* [FEATURE] Add ability to update a silence on `api/v1/silences` POST endpoint (See #765) |
749 | -* [FEATURE] Return alert status on `api/v1/alerts` GET endpoint |
750 | -* [FEATURE] Serve silence state on `api/v1/silences` GET endpoint |
751 | -* [FEATURE] Add ability to specify a route prefix |
752 | -* [FEATURE] Add option to disable AM listening on mesh port |
753 | -* [ENHANCEMENT] Add ability to specify `filter` string and `silenced` flag on `api/v1/alerts` GET endpoint |
754 | -* [ENHANCEMENT] Update `cache-control` to prevent caching for web assets in general. |
755 | -* [ENHANCEMENT] Serve web assets by alertmanager instead of external CDN (See #846) |
756 | -* [ENHANCEMENT] Elide secrets in alertmanager config (See #840) |
757 | -* [ENHANCEMENT] AMTool: Move config file to a more consistent location (See #843) |
758 | -* [BUGFIX] Enable builds for Solaris/Illumos |
759 | -* [BUGFIX] Load web assets based on url path (See #323) |
760 | - |
761 | -## 0.6.2 / 2017-05-09 |
762 | - |
763 | -* [BUGFIX] Correctly link to silences from alert again |
764 | -* [BUGFIX] Correctly hide silenced/show active alerts in UI again |
765 | -* [BUGFIX] Fix regression of alerts not being displayed until first processing |
766 | -* [BUGFIX] Fix internal usage of wrong lock for silence markers |
767 | -* [BUGFIX] Adapt amtool's API parsing to recent API changes |
768 | -* [BUGFIX] Correctly marshal regexes in config JSON response |
769 | -* [CHANGE] Anchor silence regex matchers to be consistent with Prometheus |
770 | -* [ENHANCEMENT] Error if root route is using `continue` keyword |
771 | - |
772 | -## 0.6.1 / 2017-04-28 |
773 | - |
774 | -* [BUGFIX] Fix incorrectly serialized hash for notification providers. |
775 | -* [ENHANCEMENT] Add processing status field to alerts. |
776 | -* [FEATURE] Add config hash metric. |
777 | - |
778 | -## 0.6.0 / 2017-04-25 |
779 | - |
780 | -* [BUGFIX] Add `groupKey` to `alerts/groups` endpoint https://github.com/prometheus/alertmanager/pull/576 |
781 | -* [BUGFIX] Only notify on firing alerts https://github.com/prometheus/alertmanager/pull/595 |
782 | -* [BUGFIX] Correctly marshal regex's in config for routing tree https://github.com/prometheus/alertmanager/pull/602 |
783 | -* [BUGFIX] Prevent panic when failing to load config https://github.com/prometheus/alertmanager/pull/607 |
784 | -* [BUGFIX] Prevent panic when alertmanager is started with an empty `-mesh.peer` https://github.com/prometheus/alertmanager/pull/726 |
785 | -* [CHANGE] Rename VictorOps config variables https://github.com/prometheus/alertmanager/pull/667 |
786 | -* [CHANGE] No longer generate releases for openbsd/arm https://github.com/prometheus/alertmanager/pull/732 |
787 | -* [ENHANCEMENT] Add `DELETE` as accepted CORS method https://github.com/prometheus/alertmanager/commit/0ecc59076ca6b4cbb63252fa7720a3d89d1c81d3 |
788 | -* [ENHANCEMENT] Switch to using `gogoproto` for protobuf https://github.com/prometheus/alertmanager/pull/715 |
789 | -* [ENHANCEMENT] Include notifier type in logs and errors https://github.com/prometheus/alertmanager/pull/702 |
790 | -* [FEATURE] Expose mesh peers on status page https://github.com/prometheus/alertmanager/pull/644 |
791 | -* [FEATURE] Add `reReplaceAll` template function https://github.com/prometheus/alertmanager/pull/639 |
792 | -* [FEATURE] Allow label-based filtering alerts/silences through API https://github.com/prometheus/alertmanager/pull/633 |
793 | -* [FEATURE] Add commandline tool for interacting with alertmanager https://github.com/prometheus/alertmanager/pull/636 |
794 | - |
795 | -## 0.5.1 / 2016-11-24 |
796 | - |
797 | -* [BUGFIX] Fix crash caused by race condition in silencing |
798 | -* [ENHANCEMENT] Improve logging of API errors |
799 | -* [ENHANCEMENT] Add metrics for the notification log |
800 | - |
801 | -## 0.5.0 / 2016-11-01 |
802 | - |
803 | -This release requires a storage wipe. It contains fundamental internal |
804 | -changes that came with implementing the high availability mode. |
805 | - |
806 | -* [FEATURE] Alertmanager clustering for high availability |
807 | -* [FEATURE] Garbage collection of old silences and notification logs |
808 | -* [CHANGE] New storage format |
809 | -* [CHANGE] Stricter silence semantics for consistent historical view |
810 | - |
811 | -## 0.4.2 / 2016-09-02 |
812 | - |
813 | -* [BUGFIX] Fix broken regex checkbox in silence form |
814 | -* [BUGFIX] Simplify inconsistent silence update behavior |
815 | - |
816 | -## 0.4.1 / 2016-08-31 |
817 | - |
818 | -* [BUGFIX] Wait for silence query to finish instead of showing error |
819 | -* [BUGFIX] Fix sorting of silences |
820 | -* [BUGFIX] Provide visual feedback after creating a silence |
821 | -* [BUGFIX] Fix styling of silences |
822 | -* [ENHANCEMENT] Provide cleaner API silence interface |
823 | - |
824 | -## 0.4.0 / 2016-08-23 |
825 | - |
826 | -* [FEATURE] Silences are now paginated in the web ui |
827 | -* [CHANGE] Failure to start on unparsed flags |
828 | - |
829 | -## 0.3.0 / 2016-07-07 |
830 | - |
831 | -* [CHANGE] Alerts are purely in memory and no longer persistent across restarts |
832 | -* [FEATURE] Add SMTP LOGIN authentication mechanism |
833 | - |
834 | -## 0.2.1 / 2016-06-23 |
835 | - |
836 | -* [ENHANCEMENT] Allow inheritance of route receiver |
837 | -* [ENHANCEMENT] Add silence cache to silence provider |
838 | -* [BUGFIX] Fix HipChat room number in integration URL |
839 | - |
840 | -## 0.2.0 / 2016-06-17 |
841 | - |
842 | -This release uses a new storage backend based on BoltDB. You have to backup |
843 | -and wipe your former storage path to run it. |
844 | - |
845 | -* [CHANGE] Use BoltDB as data store. |
846 | -* [CHANGE] Move SMTP authentication to configuration file |
847 | -* [FEATURE] add /-/reload HTTP endpoint |
848 | -* [FEATURE] Filter silenced alerts in web UI |
849 | -* [ENHANCEMENT] reduce inhibition computation complexity |
850 | -* [ENHANCEMENT] Add support for teams and tags in OpsGenie integration |
851 | -* [BUGFIX] Handle OpsGenie responses correctly |
852 | -* [BUGFIX] Fix Pushover queue length issue |
853 | -* [BUGFIX] STARTTLS before querying auth mechanism in email integration |
854 | - |
855 | -## 0.1.1 / 2016-03-15 |
856 | -* [BUGFIX] Fix global database lock issue |
857 | -* [ENHANCEMENT] Improve SQLite alerts index |
858 | -* [ENHANCEMENT] Enable debug endpoint |
859 | - |
860 | -## 0.1.0 / 2016-02-23 |
861 | -This version is a full rewrite of the Alertmanager with a very different |
862 | -feature set. Thus, there is no meaningful changelog. |
863 | - |
864 | -Changes with respect to 0.1.0-beta2: |
865 | -* [CHANGE] Expose same data structure to templates and webhook |
866 | -* [ENHANCEMENT] Show generator URL in default templates and web UI |
867 | -* [ENHANCEMENT] Support for Slack icon_emoji field |
868 | -* [ENHANCEMENT] Expose incident key to templates and webhook data |
869 | -* [ENHANCEMENT] Allow markdown in Slack 'text' field |
870 | -* [BUGFIX] Fixed database locking issue |
871 | - |
872 | -## 0.1.0-beta2 / 2016-02-03 |
873 | -* [BUGFIX] Properly set timeout for incoming alerts with fixed start time |
874 | -* [ENHANCEMENT] Send source field in OpsGenie integration |
875 | -* [ENHANCEMENT] Improved routing configuration validation |
876 | -* [FEATURE] Basic instrumentation added |
877 | - |
878 | -## 0.1.0-beta1 / 2016-01-08 |
879 | -* [BUGFIX] Send full alert group state on each update. Fixes erroneous resolved notifications. |
880 | -* [FEATURE] HipChat integration |
881 | -* [CHANGE] Slack integration no longer sends resolved notifications by default |
882 | - |
883 | -## 0.1.0-beta0 / 2015-12-23 |
884 | -This version is a full rewrite of the Alertmanager with a very different |
885 | -feature set. Thus, there is no meaningful changelog. |
886 | - |
887 | -## 0.0.4 / 2015-09-09 |
888 | -* [BUGFIX] Fix version info string in startup message. |
889 | -* [BUGFIX] Fix Pushover notifications by setting the right priority level, as |
890 | - well as required retry and expiry intervals. |
891 | -* [FEATURE] Make it possible to link to individual alerts in the UI. |
892 | -* [FEATURE] Rearrange alert columns in UI and allow expanding more alert details. |
893 | -* [FEATURE] Add Amazon SNS notifications. |
894 | -* [FEATURE] Add OpsGenie Webhook notifications. |
895 | -* [FEATURE] Add `-web.external-url` flag to control the externally visible |
896 | - Alertmanager URL. |
897 | -* [FEATURE] Add runbook and alertmanager URLs to PagerDuty and email notifications. |
898 | -* [FEATURE] Add a GET API to /api/alerts which pulls JSON formatted |
899 | - AlertAggregates. |
900 | -* [ENHANCEMENT] Sort alerts consistently in web UI. |
901 | -* [ENHANCEMENT] Suggest to use email address as silence creator. |
902 | -* [ENHANCEMENT] Make Slack timeout configurable. |
903 | -* [ENHANCEMENT] Add channel name to error logging about Slack notifications. |
904 | -* [ENHANCEMENT] Refactoring and tests for Flowdock notifications. |
905 | -* [ENHANCEMENT] New Dockerfile using alpine-golang-make-onbuild base image. |
906 | -* [CLEANUP] Add Docker instructions and other cleanups in README.md. |
907 | -* [CLEANUP] Update Makefile.COMMON from prometheus/utils. |
908 | - |
909 | -## 0.0.3 / 2015-06-10 |
910 | -* [BUGFIX] Fix email template body writer being called with parameters in wrong order. |
911 | - |
912 | -## 0.0.2 / 2015-06-09 |
913 | - |
914 | -* [BUGFIX] Fixed silences.json permissions in Docker image. |
915 | -* [CHANGE] Changed case of API JSON properties to initial lower letter. |
916 | -* [CHANGE] Migrated logging to use http://github.com/prometheus/log. |
917 | -* [FEATURE] Flowdock notification support. |
918 | -* [FEATURE] Slack notification support. |
919 | -* [FEATURE] Generic webhook notification support. |
920 | -* [FEATURE] Support for "@"-mentions in HipChat notifications. |
921 | -* [FEATURE] Path prefix option to support reverse proxies. |
922 | -* [ENHANCEMENT] Improved web redirection and 404 behavior. |
923 | -* [CLEANUP] Updated compiled web assets from source. |
924 | -* [CLEANUP] Updated fsnotify package to its new source location. |
925 | -* [CLEANUP] Updates to README.md and AUTHORS.md. |
926 | -* [CLEANUP] Various smaller cleanups and improvements. |
927 | diff --git a/COPYRIGHT.txt b/COPYRIGHT.txt |
928 | deleted file mode 100644 |
929 | index af2570c..0000000 |
930 | --- a/COPYRIGHT.txt |
931 | +++ /dev/null |
932 | @@ -1,12 +0,0 @@ |
933 | -Copyright Prometheus Team |
934 | -Licensed under the Apache License, Version 2.0 (the "License"); |
935 | -you may not use this file except in compliance with the License. |
936 | -You may obtain a copy of the License at |
937 | - |
938 | -http://www.apache.org/licenses/LICENSE-2.0 |
939 | - |
940 | -Unless required by applicable law or agreed to in writing, software |
941 | -distributed under the License is distributed on an "AS IS" BASIS, |
942 | -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
943 | -See the License for the specific language governing permissions and |
944 | -limitations under the License. |
945 | diff --git a/Dockerfile b/Dockerfile |
946 | index 7d98d53..94e2ab5 100644 |
947 | --- a/Dockerfile |
948 | +++ b/Dockerfile |
949 | @@ -1,21 +1,40 @@ |
950 | -ARG ARCH="amd64" |
951 | -ARG OS="linux" |
952 | -FROM quay.io/prometheus/busybox-${OS}-${ARCH}:latest |
953 | -LABEL maintainer="The Prometheus Authors <prometheus-developers@googlegroups.com>" |
954 | +FROM ubuntu:focal AS snap-installer |
955 | |
956 | -ARG ARCH="amd64" |
957 | -ARG OS="linux" |
958 | -COPY .build/${OS}-${ARCH}/amtool /bin/amtool |
959 | -COPY .build/${OS}-${ARCH}/alertmanager /bin/alertmanager |
960 | -COPY examples/ha/alertmanager.yml /etc/alertmanager/alertmanager.yml |
961 | +RUN set -eux; \ |
962 | + apt-get update; \ |
963 | + DEBIAN_FRONTEND=noninteractive apt-get full-upgrade -y; \ |
964 | + DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ |
965 | + jq curl ca-certificates squashfs-tools; \ |
966 | +# taken from https://snapcraft.io/docs/build-on-docker |
967 | +# Alternatively, we can install snapd, and issue `snap download prometheus-alertmanager` |
968 | + curl -L $(curl -H 'X-Ubuntu-Series: 16' 'https://api.snapcraft.io/api/v1/snaps/details/prometheus-alertmanager?channel=20.04/edge' | jq '.download_url' -r) --output prometheus-alertmanager.snap; \ |
969 | + mkdir -p /snap; \ |
970 | + unsquashfs -d /snap/prometheus-alertmanager prometheus-alertmanager.snap |
971 | |
972 | -RUN mkdir -p /alertmanager && \ |
973 | - chown -R nobody:nogroup etc/alertmanager /alertmanager |
974 | +FROM ubuntu:focal |
975 | |
976 | -USER nobody |
977 | +ENV TZ UTC |
978 | + |
979 | +RUN set -eux; \ |
980 | + apt-get update; \ |
981 | + DEBIAN_FRONTEND=noninteractive apt-get full-upgrade -y; \ |
982 | + DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ |
983 | + tzdata; \ |
984 | + rm -rf /var/lib/apt/lists/*; \ |
985 | + mkdir -p /alertmanager |
986 | + |
987 | +COPY --from=snap-installer /snap/prometheus-alertmanager/bin/alertmanager /usr/bin/alertmanager |
988 | +COPY --from=snap-installer /snap/prometheus-alertmanager/bin/amtool /usr/bin/amtool |
989 | +COPY --from=snap-installer /snap/prometheus-alertmanager/etc/prometheus/alertmanager.yml.example /etc/alertmanager/alertmanager.yml |
990 | + |
991 | +# Copy the manifest files from the snap |
992 | +COPY --from=snap-installer /snap/prometheus-alertmanager/snap/snapcraft.yaml /usr/share/rocks/ |
993 | +COPY --from=snap-installer /snap/prometheus-alertmanager/snap/manifest.yaml /usr/share/rocks/ |
994 | + |
995 | +# Expose port, configure volume and define the entrypoint |
996 | EXPOSE 9093 |
997 | VOLUME [ "/alertmanager" ] |
998 | WORKDIR /alertmanager |
999 | -ENTRYPOINT [ "/bin/alertmanager" ] |
1000 | +ENTRYPOINT [ "/usr/bin/alertmanager" ] |
1001 | CMD [ "--config.file=/etc/alertmanager/alertmanager.yml", \ |
1002 | "--storage.path=/alertmanager" ] |
1003 | diff --git a/oci/HACKING.md b/HACKING.md |
1004 | similarity index 100% |
1005 | rename from oci/HACKING.md |
1006 | rename to HACKING.md |
1007 | diff --git a/MAINTAINERS.md b/MAINTAINERS.md |
1008 | deleted file mode 100644 |
1009 | index e45f5e2..0000000 |
1010 | --- a/MAINTAINERS.md |
1011 | +++ /dev/null |
1012 | @@ -1 +0,0 @@ |
1013 | -* Simon Pasquier <pasquier.simon@gmail.com> |
1014 | diff --git a/Makefile b/Makefile |
1015 | index 3611908..b0bede0 100644 |
1016 | --- a/Makefile |
1017 | +++ b/Makefile |
1018 | @@ -1,56 +1,26 @@ |
1019 | -# Copyright 2015 The Prometheus Authors |
1020 | -# Licensed under the Apache License, Version 2.0 (the "License"); |
1021 | -# you may not use this file except in compliance with the License. |
1022 | -# You may obtain a copy of the License at |
1023 | -# |
1024 | -# http://www.apache.org/licenses/LICENSE-2.0 |
1025 | -# |
1026 | -# Unless required by applicable law or agreed to in writing, software |
1027 | -# distributed under the License is distributed on an "AS IS" BASIS, |
1028 | -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
1029 | -# See the License for the specific language governing permissions and |
1030 | -# limitations under the License. |
1031 | - |
1032 | -# Needs to be defined before including Makefile.common to auto-generate targets |
1033 | -DOCKER_ARCHS ?= amd64 armv7 arm64 ppc64le s390x |
1034 | - |
1035 | -include Makefile.common |
1036 | - |
1037 | -FRONTEND_DIR = $(BIN_DIR)/ui/app |
1038 | -DOCKER_IMAGE_NAME ?= alertmanager |
1039 | - |
1040 | -STATICCHECK_IGNORE = |
1041 | - |
1042 | -.PHONY: build-all |
1043 | -# Will build both the front-end as well as the back-end |
1044 | -build-all: assets apiv2 build |
1045 | - |
1046 | -.PHONY: assets |
1047 | -assets: asset/assets_vfsdata.go |
1048 | - |
1049 | -asset/assets_vfsdata.go: ui/app/script.js ui/app/index.html ui/app/lib template/default.tmpl |
1050 | - GO111MODULE=$(GO111MODULE) $(GO) generate $(GOOPTS) ./asset |
1051 | - @$(GOFMT) -w ./asset |
1052 | - |
1053 | -ui/app/script.js: $(shell find ui/app/src -iname *.elm) api/v2/openapi.yaml |
1054 | - cd $(FRONTEND_DIR) && $(MAKE) script.js |
1055 | - |
1056 | -.PHONY: apiv2 |
1057 | -apiv2: api/v2/models api/v2/restapi api/v2/client |
1058 | - |
1059 | -SWAGGER = docker run \ |
1060 | - --user=$(shell id -u $(USER)):$(shell id -g $(USER)) \ |
1061 | - --rm \ |
1062 | - -v $(shell pwd):/go/src/github.com/prometheus/alertmanager \ |
1063 | - -w /go/src/github.com/prometheus/alertmanager quay.io/goswagger/swagger:v0.20.1 |
1064 | - |
1065 | -api/v2/models api/v2/restapi api/v2/client: api/v2/openapi.yaml |
1066 | - -rm -r api/v2/{client,models,restapi} |
1067 | - $(SWAGGER) generate server -f api/v2/openapi.yaml --copyright-file=COPYRIGHT.txt --exclude-main -A alertmanager --target api/v2/ |
1068 | - $(SWAGGER) generate client -f api/v2/openapi.yaml --copyright-file=COPYRIGHT.txt --skip-models --target api/v2 |
1069 | - |
1070 | -.PHONY: clean |
1071 | -clean: |
1072 | - - @rm -rf asset/assets_vfsdata.go \ |
1073 | - api/v2/models api/v2/restapi api/v2/client |
1074 | - - @cd $(FRONTEND_DIR) && $(MAKE) clean |
1075 | +RENDERDOWN ?= ../RenderDown/renderdown.py |
1076 | +PYTHON ?= python3 |
1077 | + |
1078 | +README_TEMPLATE = templates/README_DOCKERHUB.md |
1079 | + |
1080 | +HACKING_TEMPLATE = templates/HACKING_upstream.md |
1081 | + |
1082 | +all: all-doc |
1083 | + |
1084 | +all-doc: clean-doc readme |
1085 | + |
1086 | +get-templates: |
1087 | + wget -nv -e "robots=off" -nd -r -np -P templates https://git.launchpad.net/~canonical-server/ubuntu-docker-images/+git/templates/plain/templates/ |
1088 | + |
1089 | +readme: get-templates |
1090 | + mv -v $(README_TEMPLATE) templates/README.md |
1091 | + mv -v $(HACKING_TEMPLATE) templates/HACKING.md |
1092 | + $(PYTHON) $(RENDERDOWN) templates/README.md > README.md |
1093 | + $(PYTHON) $(RENDERDOWN) templates/HACKING.md > HACKING.md |
1094 | + |
1095 | +clean: clean-doc |
1096 | + |
1097 | +clean-doc: |
1098 | + rm -frv templates/ README.md |
1099 | + |
1100 | +.PHONY: readme clean clean-doc all all-doc get-templates |
1101 | diff --git a/Makefile.common b/Makefile.common |
1102 | deleted file mode 100644 |
1103 | index b1dcf89..0000000 |
1104 | --- a/Makefile.common |
1105 | +++ /dev/null |
1106 | @@ -1,296 +0,0 @@ |
1107 | -# Copyright 2018 The Prometheus Authors |
1108 | -# Licensed under the Apache License, Version 2.0 (the "License"); |
1109 | -# you may not use this file except in compliance with the License. |
1110 | -# You may obtain a copy of the License at |
1111 | -# |
1112 | -# http://www.apache.org/licenses/LICENSE-2.0 |
1113 | -# |
1114 | -# Unless required by applicable law or agreed to in writing, software |
1115 | -# distributed under the License is distributed on an "AS IS" BASIS, |
1116 | -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
1117 | -# See the License for the specific language governing permissions and |
1118 | -# limitations under the License. |
1119 | - |
1120 | - |
1121 | -# A common Makefile that includes rules to be reused in different prometheus projects. |
1122 | -# !!! Open PRs only against the prometheus/prometheus/Makefile.common repository! |
1123 | - |
1124 | -# Example usage : |
1125 | -# Create the main Makefile in the root project directory. |
1126 | -# include Makefile.common |
1127 | -# customTarget: |
1128 | -# @echo ">> Running customTarget" |
1129 | -# |
1130 | - |
1131 | -# Ensure GOBIN is not set during build so that promu is installed to the correct path |
1132 | -unexport GOBIN |
1133 | - |
1134 | -GO ?= go |
1135 | -GOFMT ?= $(GO)fmt |
1136 | -FIRST_GOPATH := $(firstword $(subst :, ,$(shell $(GO) env GOPATH))) |
1137 | -GOOPTS ?= |
1138 | -GOHOSTOS ?= $(shell $(GO) env GOHOSTOS) |
1139 | -GOHOSTARCH ?= $(shell $(GO) env GOHOSTARCH) |
1140 | - |
1141 | -GO_VERSION ?= $(shell $(GO) version) |
1142 | -GO_VERSION_NUMBER ?= $(word 3, $(GO_VERSION)) |
1143 | -PRE_GO_111 ?= $(shell echo $(GO_VERSION_NUMBER) | grep -E 'go1\.(10|[0-9])\.') |
1144 | - |
1145 | -GOVENDOR := |
1146 | -GO111MODULE := |
1147 | -ifeq (, $(PRE_GO_111)) |
1148 | - ifneq (,$(wildcard go.mod)) |
1149 | - # Enforce Go modules support just in case the directory is inside GOPATH (and for Travis CI). |
1150 | - GO111MODULE := on |
1151 | - |
1152 | - ifneq (,$(wildcard vendor)) |
1153 | - # Always use the local vendor/ directory to satisfy the dependencies. |
1154 | - GOOPTS := $(GOOPTS) -mod=vendor |
1155 | - endif |
1156 | - endif |
1157 | -else |
1158 | - ifneq (,$(wildcard go.mod)) |
1159 | - ifneq (,$(wildcard vendor)) |
1160 | -$(warning This repository requires Go >= 1.11 because of Go modules) |
1161 | -$(warning Some recipes may not work as expected as the current Go runtime is '$(GO_VERSION_NUMBER)') |
1162 | - endif |
1163 | - else |
1164 | - # This repository isn't using Go modules (yet). |
1165 | - GOVENDOR := $(FIRST_GOPATH)/bin/govendor |
1166 | - endif |
1167 | -endif |
1168 | -PROMU := $(FIRST_GOPATH)/bin/promu |
1169 | -pkgs = ./... |
1170 | - |
1171 | -ifeq (arm, $(GOHOSTARCH)) |
1172 | - GOHOSTARM ?= $(shell GOARM= $(GO) env GOARM) |
1173 | - GO_BUILD_PLATFORM ?= $(GOHOSTOS)-$(GOHOSTARCH)v$(GOHOSTARM) |
1174 | -else |
1175 | - GO_BUILD_PLATFORM ?= $(GOHOSTOS)-$(GOHOSTARCH) |
1176 | -endif |
1177 | - |
1178 | -GOTEST := $(GO) test |
1179 | -GOTEST_DIR := |
1180 | -ifneq ($(CIRCLE_JOB),) |
1181 | -ifneq ($(shell which gotestsum),) |
1182 | - GOTEST_DIR := test-results |
1183 | - GOTEST := gotestsum --junitfile $(GOTEST_DIR)/unit-tests.xml -- |
1184 | -endif |
1185 | -endif |
1186 | - |
1187 | -PROMU_VERSION ?= 0.5.0 |
1188 | - |
1189 | -GOLANGCI_LINT := |
1190 | -GOLANGCI_LINT_OPTS ?= |
1191 | -GOLANGCI_LINT_VERSION ?= v1.18.0 |
1192 | -# golangci-lint only supports linux, darwin and windows platforms on i386/amd64. |
1193 | -# windows isn't included here because of the path separator being different. |
1194 | -ifeq ($(GOHOSTOS),$(filter $(GOHOSTOS),linux darwin)) |
1195 | - ifeq ($(GOHOSTARCH),$(filter $(GOHOSTARCH),amd64 i386)) |
1196 | - GOLANGCI_LINT := $(FIRST_GOPATH)/bin/golangci-lint |
1197 | - endif |
1198 | -endif |
1199 | - |
1200 | -PREFIX ?= $(shell pwd) |
1201 | -BIN_DIR ?= $(shell pwd) |
1202 | -DOCKER_IMAGE_TAG ?= $(subst /,-,$(shell git rev-parse --abbrev-ref HEAD)) |
1203 | -DOCKERFILE_PATH ?= ./Dockerfile |
1204 | -DOCKERBUILD_CONTEXT ?= ./ |
1205 | -DOCKER_REPO ?= prom |
1206 | - |
1207 | -DOCKER_ARCHS ?= amd64 |
1208 | - |
1209 | -BUILD_DOCKER_ARCHS = $(addprefix common-docker-,$(DOCKER_ARCHS)) |
1210 | -PUBLISH_DOCKER_ARCHS = $(addprefix common-docker-publish-,$(DOCKER_ARCHS)) |
1211 | -TAG_DOCKER_ARCHS = $(addprefix common-docker-tag-latest-,$(DOCKER_ARCHS)) |
1212 | - |
1213 | -ifeq ($(GOHOSTARCH),amd64) |
1214 | - ifeq ($(GOHOSTOS),$(filter $(GOHOSTOS),linux freebsd darwin windows)) |
1215 | - # Only supported on amd64 |
1216 | - test-flags := -race |
1217 | - endif |
1218 | -endif |
1219 | - |
1220 | -# This rule is used to forward a target like "build" to "common-build". This |
1221 | -# allows a new "build" target to be defined in a Makefile which includes this |
1222 | -# one and override "common-build" without override warnings. |
1223 | -%: common-% ; |
1224 | - |
1225 | -.PHONY: common-all |
1226 | -common-all: precheck style check_license lint unused build test |
1227 | - |
1228 | -.PHONY: common-style |
1229 | -common-style: |
1230 | - @echo ">> checking code style" |
1231 | - @fmtRes=$$($(GOFMT) -d $$(find . -path ./vendor -prune -o -name '*.go' -print)); \ |
1232 | - if [ -n "$${fmtRes}" ]; then \ |
1233 | - echo "gofmt checking failed!"; echo "$${fmtRes}"; echo; \ |
1234 | - echo "Please ensure you are using $$($(GO) version) for formatting code."; \ |
1235 | - exit 1; \ |
1236 | - fi |
1237 | - |
1238 | -.PHONY: common-check_license |
1239 | -common-check_license: |
1240 | - @echo ">> checking license header" |
1241 | - @licRes=$$(for file in $$(find . -type f -iname '*.go' ! -path './vendor/*') ; do \ |
1242 | - awk 'NR<=3' $$file | grep -Eq "(Copyright|generated|GENERATED)" || echo $$file; \ |
1243 | - done); \ |
1244 | - if [ -n "$${licRes}" ]; then \ |
1245 | - echo "license header checking failed:"; echo "$${licRes}"; \ |
1246 | - exit 1; \ |
1247 | - fi |
1248 | - |
1249 | -.PHONY: common-deps |
1250 | -common-deps: |
1251 | - @echo ">> getting dependencies" |
1252 | -ifdef GO111MODULE |
1253 | - GO111MODULE=$(GO111MODULE) $(GO) mod download |
1254 | -else |
1255 | - $(GO) get $(GOOPTS) -t ./... |
1256 | -endif |
1257 | - |
1258 | -.PHONY: update-go-deps |
1259 | -update-go-deps: |
1260 | - @echo ">> updating Go dependencies" |
1261 | - @for m in $$($(GO) list -mod=readonly -m -f '{{ if and (not .Indirect) (not .Main)}}{{.Path}}{{end}}' all); do \ |
1262 | - $(GO) get $$m; \ |
1263 | - done |
1264 | - GO111MODULE=$(GO111MODULE) $(GO) mod tidy |
1265 | -ifneq (,$(wildcard vendor)) |
1266 | - GO111MODULE=$(GO111MODULE) $(GO) mod vendor |
1267 | -endif |
1268 | - |
1269 | -.PHONY: common-test-short |
1270 | -common-test-short: $(GOTEST_DIR) |
1271 | - @echo ">> running short tests" |
1272 | - GO111MODULE=$(GO111MODULE) $(GOTEST) -short $(GOOPTS) $(pkgs) |
1273 | - |
1274 | -.PHONY: common-test |
1275 | -common-test: $(GOTEST_DIR) |
1276 | - @echo ">> running all tests" |
1277 | - GO111MODULE=$(GO111MODULE) $(GOTEST) $(test-flags) $(GOOPTS) $(pkgs) |
1278 | - |
1279 | -$(GOTEST_DIR): |
1280 | - @mkdir -p $@ |
1281 | - |
1282 | -.PHONY: common-format |
1283 | -common-format: |
1284 | - @echo ">> formatting code" |
1285 | - GO111MODULE=$(GO111MODULE) $(GO) fmt $(pkgs) |
1286 | - |
1287 | -.PHONY: common-vet |
1288 | -common-vet: |
1289 | - @echo ">> vetting code" |
1290 | - GO111MODULE=$(GO111MODULE) $(GO) vet $(GOOPTS) $(pkgs) |
1291 | - |
1292 | -.PHONY: common-lint |
1293 | -common-lint: $(GOLANGCI_LINT) |
1294 | -ifdef GOLANGCI_LINT |
1295 | - @echo ">> running golangci-lint" |
1296 | -ifdef GO111MODULE |
1297 | -# 'go list' needs to be executed before staticcheck to prepopulate the modules cache. |
1298 | -# Otherwise staticcheck might fail randomly for some reason not yet explained. |
1299 | - GO111MODULE=$(GO111MODULE) $(GO) list -e -compiled -test=true -export=false -deps=true -find=false -tags= -- ./... > /dev/null |
1300 | - GO111MODULE=$(GO111MODULE) $(GOLANGCI_LINT) run $(GOLANGCI_LINT_OPTS) $(pkgs) |
1301 | -else |
1302 | - $(GOLANGCI_LINT) run $(pkgs) |
1303 | -endif |
1304 | -endif |
1305 | - |
1306 | -# For backward-compatibility. |
1307 | -.PHONY: common-staticcheck |
1308 | -common-staticcheck: lint |
1309 | - |
1310 | -.PHONY: common-unused |
1311 | -common-unused: $(GOVENDOR) |
1312 | -ifdef GOVENDOR |
1313 | - @echo ">> running check for unused packages" |
1314 | - @$(GOVENDOR) list +unused | grep . && exit 1 || echo 'No unused packages' |
1315 | -else |
1316 | -ifdef GO111MODULE |
1317 | - @echo ">> running check for unused/missing packages in go.mod" |
1318 | - GO111MODULE=$(GO111MODULE) $(GO) mod tidy |
1319 | -ifeq (,$(wildcard vendor)) |
1320 | - @git diff --exit-code -- go.sum go.mod |
1321 | -else |
1322 | - @echo ">> running check for unused packages in vendor/" |
1323 | - GO111MODULE=$(GO111MODULE) $(GO) mod vendor |
1324 | - @git diff --exit-code -- go.sum go.mod vendor/ |
1325 | -endif |
1326 | -endif |
1327 | -endif |
1328 | - |
1329 | -.PHONY: common-build |
1330 | -common-build: promu |
1331 | - @echo ">> building binaries" |
1332 | - GO111MODULE=$(GO111MODULE) $(PROMU) build --prefix $(PREFIX) $(PROMU_BINARIES) |
1333 | - |
1334 | -.PHONY: common-tarball |
1335 | -common-tarball: promu |
1336 | - @echo ">> building release tarball" |
1337 | - $(PROMU) tarball --prefix $(PREFIX) $(BIN_DIR) |
1338 | - |
1339 | -.PHONY: common-docker $(BUILD_DOCKER_ARCHS) |
1340 | -common-docker: $(BUILD_DOCKER_ARCHS) |
1341 | -$(BUILD_DOCKER_ARCHS): common-docker-%: |
1342 | - docker build -t "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(DOCKER_IMAGE_TAG)" \ |
1343 | - -f $(DOCKERFILE_PATH) \ |
1344 | - --build-arg ARCH="$*" \ |
1345 | - --build-arg OS="linux" \ |
1346 | - $(DOCKERBUILD_CONTEXT) |
1347 | - |
1348 | -.PHONY: common-docker-publish $(PUBLISH_DOCKER_ARCHS) |
1349 | -common-docker-publish: $(PUBLISH_DOCKER_ARCHS) |
1350 | -$(PUBLISH_DOCKER_ARCHS): common-docker-publish-%: |
1351 | - docker push "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(DOCKER_IMAGE_TAG)" |
1352 | - |
1353 | -.PHONY: common-docker-tag-latest $(TAG_DOCKER_ARCHS) |
1354 | -common-docker-tag-latest: $(TAG_DOCKER_ARCHS) |
1355 | -$(TAG_DOCKER_ARCHS): common-docker-tag-latest-%: |
1356 | - docker tag "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(DOCKER_IMAGE_TAG)" "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:latest" |
1357 | - |
1358 | -.PHONY: common-docker-manifest |
1359 | -common-docker-manifest: |
1360 | - DOCKER_CLI_EXPERIMENTAL=enabled docker manifest create -a "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME):$(DOCKER_IMAGE_TAG)" $(foreach ARCH,$(DOCKER_ARCHS),$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$(ARCH):$(DOCKER_IMAGE_TAG)) |
1361 | - DOCKER_CLI_EXPERIMENTAL=enabled docker manifest push "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME):$(DOCKER_IMAGE_TAG)" |
1362 | - |
1363 | -.PHONY: promu |
1364 | -promu: $(PROMU) |
1365 | - |
1366 | -$(PROMU): |
1367 | - mkdir -p $(FIRST_GOPATH)/bin |
1368 | - cp oci/promu/promu-$(PROMU_VERSION).$(GO_BUILD_PLATFORM)/promu $(FIRST_GOPATH)/bin/promu |
1369 | - |
1370 | -.PHONY: proto |
1371 | -proto: |
1372 | - @echo ">> generating code from proto files" |
1373 | - @./scripts/genproto.sh |
1374 | - |
1375 | -ifdef GOLANGCI_LINT |
1376 | -$(GOLANGCI_LINT): |
1377 | - mkdir -p $(FIRST_GOPATH)/bin |
1378 | - curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/$(GOLANGCI_LINT_VERSION)/install.sh \ |
1379 | - | sed -e '/install -d/d' \ |
1380 | - | sh -s -- -b $(FIRST_GOPATH)/bin $(GOLANGCI_LINT_VERSION) |
1381 | -endif |
1382 | - |
1383 | -ifdef GOVENDOR |
1384 | -.PHONY: $(GOVENDOR) |
1385 | -$(GOVENDOR): |
1386 | - GOOS= GOARCH= $(GO) get -u github.com/kardianos/govendor |
1387 | -endif |
1388 | - |
1389 | -.PHONY: precheck |
1390 | -precheck:: |
1391 | - |
1392 | -define PRECHECK_COMMAND_template = |
1393 | -precheck:: $(1)_precheck |
1394 | - |
1395 | -PRECHECK_COMMAND_$(1) ?= $(1) $$(strip $$(PRECHECK_OPTIONS_$(1))) |
1396 | -.PHONY: $(1)_precheck |
1397 | -$(1)_precheck: |
1398 | - @if ! $$(PRECHECK_COMMAND_$(1)) 1>/dev/null 2>&1; then \ |
1399 | - echo "Execution of '$$(PRECHECK_COMMAND_$(1))' command failed. Is $(1) installed?"; \ |
1400 | - exit 1; \ |
1401 | - fi |
1402 | -endef |
1403 | diff --git a/NOTICE b/NOTICE |
1404 | deleted file mode 100644 |
1405 | index f5d0bbb..0000000 |
1406 | --- a/NOTICE |
1407 | +++ /dev/null |
1408 | @@ -1,18 +0,0 @@ |
1409 | -Prometheus Alertmanager |
1410 | -Copyright 2013-2015 The Prometheus Authors |
1411 | - |
1412 | -This product includes software developed at |
1413 | -SoundCloud Ltd. (http://soundcloud.com/). |
1414 | - |
1415 | - |
1416 | -The following components are included in this product: |
1417 | - |
1418 | -Bootstrap |
1419 | -http://getbootstrap.com |
1420 | -Copyright 2011-2014 Twitter, Inc. |
1421 | -Licensed under the MIT License |
1422 | - |
1423 | -bootstrap-datetimepicker.js |
1424 | -http://www.eyecon.ro/bootstrap-datepicker |
1425 | -Copyright 2012 Stefan Petre |
1426 | -Licensed under the Apache License, Version 2.0 |
1427 | diff --git a/Procfile b/Procfile |
1428 | deleted file mode 100644 |
1429 | index ab15cfc..0000000 |
1430 | --- a/Procfile |
1431 | +++ /dev/null |
1432 | @@ -1,5 +0,0 @@ |
1433 | -a1: ./alertmanager --log.level=debug --storage.path=$TMPDIR/a1 --web.listen-address=:9093 --cluster.listen-address=127.0.0.1:8001 --config.file=examples/ha/alertmanager.yml |
1434 | -a2: ./alertmanager --log.level=debug --storage.path=$TMPDIR/a2 --web.listen-address=:9094 --cluster.listen-address=127.0.0.1:8002 --cluster.peer=127.0.0.1:8001 --config.file=examples/ha/alertmanager.yml |
1435 | -a3: ./alertmanager --log.level=debug --storage.path=$TMPDIR/a3 --web.listen-address=:9095 --cluster.listen-address=127.0.0.1:8003 --cluster.peer=127.0.0.1:8001 --config.file=examples/ha/alertmanager.yml |
1436 | -wh: go run ./examples/webhook/echo.go |
1437 | - |
1438 | diff --git a/README.md b/README.md |
1439 | index c7a3683..6b2c643 100644 |
1440 | --- a/README.md |
1441 | +++ b/README.md |
1442 | @@ -1,406 +1,89 @@ |
1443 | -# Alertmanager [![CircleCI](https://circleci.com/gh/prometheus/alertmanager/tree/master.svg?style=shield)][circleci] |
1444 | +# Prometheus Alertmanager | Ubuntu |
1445 | |
1446 | -[![Docker Repository on Quay](https://quay.io/repository/prometheus/alertmanager/status "Docker Repository on Quay")][quay] |
1447 | -[![Docker Pulls](https://img.shields.io/docker/pulls/prom/alertmanager.svg?maxAge=604800)][hub] |
1448 | +Current Prometheus Alertmanager Docker Image from Ubuntu. Receives security updates and rolls to newer Prometheus Alertmanager or Ubuntu LTS. This repository is exempted from per-user rate limits. For [LTS Docker Image](https://ubuntu.com/security/docker-images) versions of this image, see `lts/prometheus-alertmanager`. |
1449 | |
1450 | -The Alertmanager handles alerts sent by client applications such as the Prometheus server. It takes care of deduplicating, grouping, and routing them to the correct receiver integrations such as email, PagerDuty, or OpsGenie. It also takes care of silencing and inhibition of alerts. |
1451 | |
1452 | -* [Documentation](http://prometheus.io/docs/alerting/alertmanager/) |
1453 | +## About Prometheus Alertmanager |
1454 | |
1455 | -## Install |
1456 | +The Alertmanager handles alerts sent by client applications such as the Prometheus server. It takes care of deduplicating, grouping, and routing them to the correct receiver integration such as email, PagerDuty, or OpsGenie. It also takes care of silencing and inhibition of alerts. Read more on the [Prometheus Alertmanager website](https://prometheus.io/docs/alerting/latest/alertmanager/). |
1457 | |
1458 | -There are various ways of installing Alertmanager. |
1459 | |
1460 | -### Precompiled binaries |
1461 | +## Tags and Architectures |
1462 | +![LTS](https://assets.ubuntu.com/v1/0a5ff561-LTS%402x.png?h=17) |
1463 | +Up to 5 years free security maintenance `from lts/prometheus-alertmanager`. |
1464 | |
1465 | -Precompiled binaries for released versions are available in the |
1466 | -[*download* section](https://prometheus.io/download/) |
1467 | -on [prometheus.io](https://prometheus.io). Using the latest production release binary |
1468 | -is the recommended way of installing Alertmanager. |
1469 | +![ESM](https://assets.ubuntu.com/v1/572f3fbd-ESM%402x.png?h=17) |
1470 | +Up to 10 years customer security maintenance `from store/canonical/prometheus-alertmanager`. |
1471 | |
1472 | -### Docker images |
1473 | +_Tags in italics are not available in ubuntu/prometheus-alertmanager but are shown here for completeness._ |
1474 | |
1475 | -Docker images are available on [Quay.io](https://quay.io/repository/prometheus/alertmanager). |
1476 | +| Channel Tag | | | Currently | Architectures | |
1477 | +|---|---|---|---|---| |
1478 | +| **`0.21-20.04_beta`** | | | Prometheus Alertmanager 0.21.0 on Ubuntu 20.04 LTS | `amd64`, `arm64`, `ppc64el`, `s390x` | |
1479 | +| _`track_risk`_ | |
1480 | |
1481 | -### Compiling the binary |
1482 | +Channel tag shows the most stable channel for that track ordered `stable`, `candidate`, `beta`, `edge`. More risky channels are always implicitly available. So if `beta` is listed, you can also pull `edge`. If `candidate` is listed, you can pull `beta` and `edge`. When `stable` is listed, all four are available. Images are guaranteed to progress through the sequence `edge`, `beta`, `candidate` before `stable`. |
1483 | |
1484 | -You can either `go get` it: |
1485 | |
1486 | -``` |
1487 | -$ GO15VENDOREXPERIMENT=1 go get github.com/prometheus/alertmanager/cmd/... |
1488 | -# cd $GOPATH/src/github.com/prometheus/alertmanager |
1489 | -$ alertmanager --config.file=<your_file> |
1490 | -``` |
1491 | - |
1492 | -Or clone the repository and build manually: |
1493 | - |
1494 | -``` |
1495 | -$ mkdir -p $GOPATH/src/github.com/prometheus |
1496 | -$ cd $GOPATH/src/github.com/prometheus |
1497 | -$ git clone https://github.com/prometheus/alertmanager.git |
1498 | -$ cd alertmanager |
1499 | -$ make build |
1500 | -$ ./alertmanager --config.file=<your_file> |
1501 | -``` |
1502 | - |
1503 | -You can also build just one of the binaries in this repo by passing a name to the build function: |
1504 | -``` |
1505 | -$ make build BINARIES=amtool |
1506 | -``` |
1507 | - |
1508 | -## Example |
1509 | - |
1510 | -This is an example configuration that should cover most relevant aspects of the new YAML configuration format. The full documentation of the configuration can be found [here](https://prometheus.io/docs/alerting/configuration/). |
1511 | - |
1512 | -```yaml |
1513 | -global: |
1514 | - # The smarthost and SMTP sender used for mail notifications. |
1515 | - smtp_smarthost: 'localhost:25' |
1516 | - smtp_from: 'alertmanager@example.org' |
1517 | - |
1518 | -# The root route on which each incoming alert enters. |
1519 | -route: |
1520 | - # The root route must not have any matchers as it is the entry point for |
1521 | - # all alerts. It needs to have a receiver configured so alerts that do not |
1522 | - # match any of the sub-routes are sent to someone. |
1523 | - receiver: 'team-X-mails' |
1524 | - |
1525 | - # The labels by which incoming alerts are grouped together. For example, |
1526 | - # multiple alerts coming in for cluster=A and alertname=LatencyHigh would |
1527 | - # be batched into a single group. |
1528 | - # |
1529 | - # To aggregate by all possible labels use '...' as the sole label name. |
1530 | - # This effectively disables aggregation entirely, passing through all |
1531 | - # alerts as-is. This is unlikely to be what you want, unless you have |
1532 | - # a very low alert volume or your upstream notification system performs |
1533 | - # its own grouping. Example: group_by: [...] |
1534 | - group_by: ['alertname', 'cluster'] |
1535 | - |
1536 | - # When a new group of alerts is created by an incoming alert, wait at |
1537 | - # least 'group_wait' to send the initial notification. |
1538 | - # This way ensures that you get multiple alerts for the same group that start |
1539 | - # firing shortly after another are batched together on the first |
1540 | - # notification. |
1541 | - group_wait: 30s |
1542 | - |
1543 | - # When the first notification was sent, wait 'group_interval' to send a batch |
1544 | - # of new alerts that started firing for that group. |
1545 | - group_interval: 5m |
1546 | - |
1547 | - # If an alert has successfully been sent, wait 'repeat_interval' to |
1548 | - # resend them. |
1549 | - repeat_interval: 3h |
1550 | - |
1551 | - # All the above attributes are inherited by all child routes and can |
1552 | - # overwritten on each. |
1553 | - |
1554 | - # The child route trees. |
1555 | - routes: |
1556 | - # This routes performs a regular expression match on alert labels to |
1557 | - # catch alerts that are related to a list of services. |
1558 | - - match_re: |
1559 | - service: ^(foo1|foo2|baz)$ |
1560 | - receiver: team-X-mails |
1561 | - |
1562 | - # The service has a sub-route for critical alerts, any alerts |
1563 | - # that do not match, i.e. severity != critical, fall-back to the |
1564 | - # parent node and are sent to 'team-X-mails' |
1565 | - routes: |
1566 | - - match: |
1567 | - severity: critical |
1568 | - receiver: team-X-pager |
1569 | - |
1570 | - - match: |
1571 | - service: files |
1572 | - receiver: team-Y-mails |
1573 | - |
1574 | - routes: |
1575 | - - match: |
1576 | - severity: critical |
1577 | - receiver: team-Y-pager |
1578 | - |
1579 | - # This route handles all alerts coming from a database service. If there's |
1580 | - # no team to handle it, it defaults to the DB team. |
1581 | - - match: |
1582 | - service: database |
1583 | - |
1584 | - receiver: team-DB-pager |
1585 | - # Also group alerts by affected database. |
1586 | - group_by: [alertname, cluster, database] |
1587 | - |
1588 | - routes: |
1589 | - - match: |
1590 | - owner: team-X |
1591 | - receiver: team-X-pager |
1592 | - |
1593 | - - match: |
1594 | - owner: team-Y |
1595 | - receiver: team-Y-pager |
1596 | - |
1597 | - |
1598 | -# Inhibition rules allow to mute a set of alerts given that another alert is |
1599 | -# firing. |
1600 | -# We use this to mute any warning-level notifications if the same alert is |
1601 | -# already critical. |
1602 | -inhibit_rules: |
1603 | -- source_match: |
1604 | - severity: 'critical' |
1605 | - target_match: |
1606 | - severity: 'warning' |
1607 | - # Apply inhibition if the alertname is the same. |
1608 | - # CAUTION: |
1609 | - # If all label names listed in `equal` are missing |
1610 | - # from both the source and target alerts, |
1611 | - # the inhibition rule will apply! |
1612 | - equal: ['alertname'] |
1613 | - |
1614 | - |
1615 | -receivers: |
1616 | -- name: 'team-X-mails' |
1617 | - email_configs: |
1618 | - - to: 'team-X+alerts@example.org, team-Y+alerts@example.org' |
1619 | - |
1620 | -- name: 'team-X-pager' |
1621 | - email_configs: |
1622 | - - to: 'team-X+alerts-critical@example.org' |
1623 | - pagerduty_configs: |
1624 | - - routing_key: <team-X-key> |
1625 | - |
1626 | -- name: 'team-Y-mails' |
1627 | - email_configs: |
1628 | - - to: 'team-Y+alerts@example.org' |
1629 | - |
1630 | -- name: 'team-Y-pager' |
1631 | - pagerduty_configs: |
1632 | - - routing_key: <team-Y-key> |
1633 | - |
1634 | -- name: 'team-DB-pager' |
1635 | - pagerduty_configs: |
1636 | - - routing_key: <team-DB-key> |
1637 | -``` |
1638 | - |
1639 | -## API |
1640 | - |
1641 | -The current Alertmanager API is version 2. This API is fully generated via the |
1642 | -[OpenAPI project](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md) |
1643 | -and [Go Swagger](https://github.com/go-swagger/go-swagger/) with the exception |
1644 | -of the HTTP handlers themselves. The API specification can be found in |
1645 | -[api/v2/openapi.yaml](api/v2/openapi.yaml). A HTML rendered version can be |
1646 | -accessed [here](http://petstore.swagger.io/?url=https://raw.githubusercontent.com/prometheus/alertmanager/master/api/v2/openapi.yaml). |
1647 | -Clients can be easily generated via any OpenAPI generator for all major languages. |
1648 | +## Usage |
1649 | |
1650 | -With the default config, endpoints are accessed under a `/api/v1` or `/api/v2` prefix. |
1651 | -The v2 `/status` endpoint would be `/api/v2/status`. If `--web.route-prefix` is set then API routes are |
1652 | -prefixed with that as well, so `--web.route-prefix=/alertmanager/` would |
1653 | -relate to `/alertmanager/api/v2/status`. |
1654 | - |
1655 | -_API v2 is still under heavy development and thereby subject to change._ |
1656 | - |
1657 | -## amtool |
1658 | - |
1659 | -`amtool` is a cli tool for interacting with the Alertmanager API. It is bundled with all releases of Alertmanager. |
1660 | - |
1661 | -### Install |
1662 | - |
1663 | -Alternatively you can install with: |
1664 | -``` |
1665 | -go get github.com/prometheus/alertmanager/cmd/amtool |
1666 | -``` |
1667 | - |
1668 | -### Examples |
1669 | - |
1670 | -View all currently firing alerts: |
1671 | -``` |
1672 | -$ amtool alert |
1673 | -Alertname Starts At Summary |
1674 | -Test_Alert 2017-08-02 18:30:18 UTC This is a testing alert! |
1675 | -Test_Alert 2017-08-02 18:30:18 UTC This is a testing alert! |
1676 | -Check_Foo_Fails 2017-08-02 18:30:18 UTC This is a testing alert! |
1677 | -Check_Foo_Fails 2017-08-02 18:30:18 UTC This is a testing alert! |
1678 | -``` |
1679 | - |
1680 | -View all currently firing alerts with extended output: |
1681 | -``` |
1682 | -$ amtool -o extended alert |
1683 | -Labels Annotations Starts At Ends At Generator URL |
1684 | -alertname="Test_Alert" instance="node0" link="https://example.com" summary="This is a testing alert!" 2017-08-02 18:31:24 UTC 0001-01-01 00:00:00 UTC http://my.testing.script.local |
1685 | -alertname="Test_Alert" instance="node1" link="https://example.com" summary="This is a testing alert!" 2017-08-02 18:31:24 UTC 0001-01-01 00:00:00 UTC http://my.testing.script.local |
1686 | -alertname="Check_Foo_Fails" instance="node0" link="https://example.com" summary="This is a testing alert!" 2017-08-02 18:31:24 UTC 0001-01-01 00:00:00 UTC http://my.testing.script.local |
1687 | -alertname="Check_Foo_Fails" instance="node1" link="https://example.com" summary="This is a testing alert!" 2017-08-02 18:31:24 UTC 0001-01-01 00:00:00 UTC http://my.testing.script.local |
1688 | -``` |
1689 | +Launch this image locally: |
1690 | |
1691 | -In addition to viewing alerts, you can use the rich query syntax provided by Alertmanager: |
1692 | -``` |
1693 | -$ amtool -o extended alert query alertname="Test_Alert" |
1694 | -Labels Annotations Starts At Ends At Generator URL |
1695 | -alertname="Test_Alert" instance="node0" link="https://example.com" summary="This is a testing alert!" 2017-08-02 18:31:24 UTC 0001-01-01 00:00:00 UTC http://my.testing.script.local |
1696 | -alertname="Test_Alert" instance="node1" link="https://example.com" summary="This is a testing alert!" 2017-08-02 18:31:24 UTC 0001-01-01 00:00:00 UTC http://my.testing.script.local |
1697 | - |
1698 | -$ amtool -o extended alert query instance=~".+1" |
1699 | -Labels Annotations Starts At Ends At Generator URL |
1700 | -alertname="Test_Alert" instance="node1" link="https://example.com" summary="This is a testing alert!" 2017-08-02 18:31:24 UTC 0001-01-01 00:00:00 UTC http://my.testing.script.local |
1701 | -alertname="Check_Foo_Fails" instance="node1" link="https://example.com" summary="This is a testing alert!" 2017-08-02 18:31:24 UTC 0001-01-01 00:00:00 UTC http://my.testing.script.local |
1702 | - |
1703 | -$ amtool -o extended alert query alertname=~"Test.*" instance=~".+1" |
1704 | -Labels Annotations Starts At Ends At Generator URL |
1705 | -alertname="Test_Alert" instance="node1" link="https://example.com" summary="This is a testing alert!" 2017-08-02 18:31:24 UTC 0001-01-01 00:00:00 UTC http://my.testing.script.local |
1706 | +```sh |
1707 | +docker run -d --name prometheus-alertmanager-container -e TZ=UTC -p 30093:9093 ubuntu/prometheus-alertmanager:0.21-20.04_beta |
1708 | ``` |
1709 | +Access your Prometheus Alertmanager server at `localhost:30093`. |
1710 | |
1711 | -Silence an alert: |
1712 | -``` |
1713 | -$ amtool silence add alertname=Test_Alert |
1714 | -b3ede22e-ca14-4aa0-932c-ca2f3445f926 |
1715 | +#### Parameters |
1716 | |
1717 | -$ amtool silence add alertname="Test_Alert" instance=~".+0" |
1718 | -e48cb58a-0b17-49ba-b734-3585139b1d25 |
1719 | -``` |
1720 | +| Parameter | Description | |
1721 | +|---|---| |
1722 | +| `-e TZ=UTC` | Timezone. | |
1723 | +| `-p 30093:9093` | Expose Prometheus Alertmanager on `localhost:30093`. | |
1724 | +| `-v /path/to/alertmanager.yml:/etc/prometheus/alertmanager.yml` | Local [configuration file](https://www.prometheus.io/docs/alerting/latest/configuration/) `alertmanager.yml` (try [this example](https://git.launchpad.net/~canonical-server/ubuntu-docker-images/+git/prometheus-alertmanager/plain/oci/examples/config/alertmanager.yml)). | |
1725 | +| `-v /path/to/persisted/data:/alertmanager` | Persist data instead of initializing a new database for each newly launched container. **Important note**: the directory you will be using to persist the data needs to belong to `nogroup:nobody`. You can run `chown nogroup:nobody <path_to_persist_data>` before launching your container. | |
1726 | |
1727 | -View silences: |
1728 | -``` |
1729 | -$ amtool silence query |
1730 | -ID Matchers Ends At Created By Comment |
1731 | -b3ede22e-ca14-4aa0-932c-ca2f3445f926 alertname=Test_Alert 2017-08-02 19:54:50 UTC kellel |
1732 | |
1733 | -$ amtool silence query instance=~".+0" |
1734 | -ID Matchers Ends At Created By Comment |
1735 | -e48cb58a-0b17-49ba-b734-3585139b1d25 alertname=Test_Alert instance=~.+0 2017-08-02 22:41:39 UTC kellel |
1736 | -``` |
1737 | +#### Testing/Debugging |
1738 | |
1739 | -Expire a silence: |
1740 | -``` |
1741 | -$ amtool silence expire b3ede22e-ca14-4aa0-932c-ca2f3445f926 |
1742 | -``` |
1743 | +To debug the container: |
1744 | |
1745 | -Expire all silences matching a query: |
1746 | +```sh |
1747 | +docker logs -f prometheus-alertmanager-container |
1748 | ``` |
1749 | -$ amtool silence query instance=~".+0" |
1750 | -ID Matchers Ends At Created By Comment |
1751 | -e48cb58a-0b17-49ba-b734-3585139b1d25 alertname=Test_Alert instance=~.+0 2017-08-02 22:41:39 UTC kellel |
1752 | - |
1753 | -$ amtool silence expire $(amtool silence -q query instance=~".+0") |
1754 | |
1755 | -$ amtool silence query instance=~".+0" |
1756 | +To get an interactive shell: |
1757 | |
1758 | +```sh |
1759 | +docker exec -it prometheus-alertmanager-container /bin/bash |
1760 | ``` |
1761 | |
1762 | -Expire all silences: |
1763 | -``` |
1764 | -$ amtool silence expire $(amtool silence query -q) |
1765 | -``` |
1766 | |
1767 | -### Configuration |
1768 | +## Deploy with Kubernetes |
1769 | |
1770 | -`amtool` allows a configuration file to specify some options for convenience. The default configuration file paths are `$HOME/.config/amtool/config.yml` or `/etc/amtool/config.yml` |
1771 | +Works with any Kubernetes; if you don't have one, we recommend you [install MicroK8s](https://microk8s.io/) and `microk8s.enable dns storage` then `snap alias microk8s.kubectl kubectl`. |
1772 | |
1773 | -An example configuration file might look like the following: |
1774 | +Download |
1775 | +[alertmanager.yml](https://git.launchpad.net/~canonical-server/ubuntu-docker-images/+git/prometheus-alertmanager/plain/oci/examples/config/alertmanager.yml) and |
1776 | +[prometheus-alertmanager-deployment.yml](https://git.launchpad.net/~canonical-server/ubuntu-docker-images/+git/prometheus-alertmanager/plain/oci/examples/alertmanager-deployment.yml) and set `containers.prometheus-alertmanager.image` in `prometheus-alertmanager-deployment.yml` to your chosen channel tag (e.g. `ubuntu/prometheus-alertmanager:0.21-20.04_beta`), then: |
1777 | |
1778 | +```sh |
1779 | +kubectl create configmap prometheus-alertmanager-config --from-file=alertmanager=alertmanager.yml |
1780 | +kubectl apply -f prometheus-alertmanager-deployment.yml |
1781 | ``` |
1782 | -# Define the path that `amtool` can find your `alertmanager` instance |
1783 | -alertmanager.url: "http://localhost:9093" |
1784 | - |
1785 | -# Override the default author. (unset defaults to your username) |
1786 | -author: me@example.com |
1787 | - |
1788 | -# Force amtool to give you an error if you don't include a comment on a silence |
1789 | -comment_required: true |
1790 | |
1791 | -# Set a default output format. (unset defaults to simple) |
1792 | -output: extended |
1793 | +You will now be able to connect to the Prometheus Alertmanager server on `localhost:30093`. |
1794 | |
1795 | -# Set a default receiver |
1796 | -receiver: team-X-pager |
1797 | -``` |
1798 | - |
1799 | -### Routes |
1800 | +## Bugs and feature requests |
1801 | |
1802 | -`amtool` allows you to visualize the routes of your configuration in form of text tree view. |
1803 | -Also you can use it to test the routing by passing it label set of an alert |
1804 | -and it prints out all receivers the alert would match ordered and separated by `,`. |
1805 | -(If you use `--verify.receivers` amtool returns error code 1 on mismatch) |
1806 | +If you find a bug in our image or want to request a specific feature, please file a bug here: |
1807 | |
1808 | -Example of usage: |
1809 | -``` |
1810 | -# View routing tree of remote Alertmanager |
1811 | -$ amtool config routes --alertmanager.url=http://localhost:9090 |
1812 | +[https://bugs.launchpad.net/ubuntu-docker-images/+filebug](https://bugs.launchpad.net/ubuntu-docker-images/+filebug) |
1813 | |
1814 | -# Test if alert matches expected receiver |
1815 | -$ amtool config routes test --config.file=doc/examples/simple.yml --tree --verify.receivers=team-X-pager service=database owner=team-X |
1816 | -``` |
1817 | +Please title the bug "`prometheus-alertmanager: <issue summary>`". Make sure to include the digest of the image you are using, from: |
1818 | |
1819 | -## High Availability |
1820 | - |
1821 | -Alertmanager's high availability is in production use at many companies and is enabled by default. |
1822 | - |
1823 | -> Important: Both UDP and TCP are needed in alertmanager 0.15 and higher for the cluster to work. |
1824 | -> - If you are using a firewall, make sure to whitelist the clustering port for both protocols. |
1825 | -> - If you are running in a container, make sure to expose the clustering port for both protocols. |
1826 | - |
1827 | -To create a highly available cluster of the Alertmanager the instances need to |
1828 | -be configured to communicate with each other. This is configured using the |
1829 | -`--cluster.*` flags. |
1830 | - |
1831 | -- `--cluster.listen-address` string: cluster listen address (default "0.0.0.0:9094"; empty string disables HA mode) |
1832 | -- `--cluster.advertise-address` string: cluster advertise address |
1833 | -- `--cluster.peer` value: initial peers (repeat flag for each additional peer) |
1834 | -- `--cluster.peer-timeout` value: peer timeout period (default "15s") |
1835 | -- `--cluster.gossip-interval` value: cluster message propagation speed |
1836 | - (default "200ms") |
1837 | -- `--cluster.pushpull-interval` value: lower values will increase |
1838 | - convergence speeds at expense of bandwidth (default "1m0s") |
1839 | -- `--cluster.settle-timeout` value: maximum time to wait for cluster |
1840 | - connections to settle before evaluating notifications. |
1841 | -- `--cluster.tcp-timeout` value: timeout value for tcp connections, reads and writes (default "10s") |
1842 | -- `--cluster.probe-timeout` value: time to wait for ack before marking node unhealthy |
1843 | - (default "500ms") |
1844 | -- `--cluster.probe-interval` value: interval between random node probes (default "1s") |
1845 | -- `--cluster.reconnect-interval` value: interval between attempting to reconnect to lost peers (default "10s") |
1846 | -- `--cluster.reconnect-timeout` value: length of time to attempt to reconnect to a lost peer (default: "6h0m0s") |
1847 | - |
1848 | -The chosen port in the `cluster.listen-address` flag is the port that needs to be |
1849 | -specified in the `cluster.peer` flag of the other peers. |
1850 | - |
1851 | -The `cluster.advertise-address` flag is required if the instance doesn't have |
1852 | -an IP address that is part of [RFC 6980](https://tools.ietf.org/html/rfc6890) |
1853 | -with a default route. |
1854 | - |
1855 | -To start a cluster of three peers on your local machine use [`goreman`](https://github.com/mattn/goreman) and the |
1856 | -Procfile within this repository. |
1857 | - |
1858 | - goreman start |
1859 | - |
1860 | -To point your Prometheus 1.4, or later, instance to multiple Alertmanagers, configure them |
1861 | -in your `prometheus.yml` configuration file, for example: |
1862 | - |
1863 | -```yaml |
1864 | -alerting: |
1865 | - alertmanagers: |
1866 | - - static_configs: |
1867 | - - targets: |
1868 | - - alertmanager1:9093 |
1869 | - - alertmanager2:9093 |
1870 | - - alertmanager3:9093 |
1871 | +```sh |
1872 | +docker images --no-trunc --quiet ubuntu/prometheus-alertmanager:<tag> |
1873 | ``` |
1874 | |
1875 | -> Important: Do not load balance traffic between Prometheus and its Alertmanagers, but instead point Prometheus to a list of all Alertmanagers. The Alertmanager implementation expects all alerts to be sent to all Alertmanagers to ensure high availability. |
1876 | - |
1877 | -### Turn off high availability |
1878 | - |
1879 | -If running Alertmanager in high availability mode is not desired, setting `--cluster.listen-address=` prevents Alertmanager from listening to incoming peer requests. |
1880 | - |
1881 | -## Contributing |
1882 | - |
1883 | -Check the [Prometheus contributing page](https://github.com/prometheus/prometheus/blob/master/CONTRIBUTING.md). |
1884 | - |
1885 | -To contribute to the user interface, refer to [ui/app/CONTRIBUTING.md](ui/app/CONTRIBUTING.md). |
1886 | - |
1887 | -## Architecture |
1888 | - |
1889 | -![](doc/arch.svg) |
1890 | - |
1891 | -## License |
1892 | - |
1893 | -Apache License 2.0, see [LICENSE](https://github.com/prometheus/alertmanager/blob/master/LICENSE). |
1894 | |
1895 | -[hub]: https://hub.docker.com/r/prom/alertmanager/ |
1896 | -[circleci]: https://circleci.com/gh/prometheus/alertmanager |
1897 | -[quay]: https://quay.io/repository/prometheus/alertmanager |
1898 | diff --git a/VERSION b/VERSION |
1899 | deleted file mode 100644 |
1900 | index 8854156..0000000 |
1901 | --- a/VERSION |
1902 | +++ /dev/null |
1903 | @@ -1 +0,0 @@ |
1904 | -0.21.0 |
1905 | diff --git a/api/api.go b/api/api.go |
1906 | deleted file mode 100644 |
1907 | index 6b4a883..0000000 |
1908 | --- a/api/api.go |
1909 | +++ /dev/null |
1910 | @@ -1,230 +0,0 @@ |
1911 | -// Copyright 2019 Prometheus Team |
1912 | -// Licensed under the Apache License, Version 2.0 (the "License"); |
1913 | -// you may not use this file except in compliance with the License. |
1914 | -// You may obtain a copy of the License at |
1915 | -// |
1916 | -// http://www.apache.org/licenses/LICENSE-2.0 |
1917 | -// |
1918 | -// Unless required by applicable law or agreed to in writing, software |
1919 | -// distributed under the License is distributed on an "AS IS" BASIS, |
1920 | -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
1921 | -// See the License for the specific language governing permissions and |
1922 | -// limitations under the License. |
1923 | - |
1924 | -package api |
1925 | - |
1926 | -import ( |
1927 | - "errors" |
1928 | - "fmt" |
1929 | - "net/http" |
1930 | - "runtime" |
1931 | - "time" |
1932 | - |
1933 | - apiv1 "github.com/prometheus/alertmanager/api/v1" |
1934 | - apiv2 "github.com/prometheus/alertmanager/api/v2" |
1935 | - "github.com/prometheus/alertmanager/cluster" |
1936 | - "github.com/prometheus/alertmanager/config" |
1937 | - "github.com/prometheus/alertmanager/dispatch" |
1938 | - "github.com/prometheus/alertmanager/provider" |
1939 | - "github.com/prometheus/alertmanager/silence" |
1940 | - "github.com/prometheus/alertmanager/types" |
1941 | - "github.com/prometheus/client_golang/prometheus" |
1942 | - "github.com/prometheus/common/model" |
1943 | - "github.com/prometheus/common/route" |
1944 | - |
1945 | - "github.com/go-kit/kit/log" |
1946 | -) |
1947 | - |
1948 | -// API represents all APIs of Alertmanager. |
1949 | -type API struct { |
1950 | - v1 *apiv1.API |
1951 | - v2 *apiv2.API |
1952 | - requestsInFlight prometheus.Gauge |
1953 | - concurrencyLimitExceeded prometheus.Counter |
1954 | - timeout time.Duration |
1955 | - inFlightSem chan struct{} |
1956 | -} |
1957 | - |
1958 | -// Options for the creation of an API object. Alerts, Silences, and StatusFunc |
1959 | -// are mandatory to set. The zero value for everything else is a safe default. |
1960 | -type Options struct { |
1961 | - // Alerts to be used by the API. Mandatory. |
1962 | - Alerts provider.Alerts |
1963 | - // Silences to be used by the API. Mandatory. |
1964 | - Silences *silence.Silences |
1965 | - // StatusFunc is used be the API to retrieve the AlertStatus of an |
1966 | - // alert. Mandatory. |
1967 | - StatusFunc func(model.Fingerprint) types.AlertStatus |
1968 | - // Peer from the gossip cluster. If nil, no clustering will be used. |
1969 | - Peer *cluster.Peer |
1970 | - // Timeout for all HTTP connections. The zero value (and negative |
1971 | - // values) result in no timeout. |
1972 | - Timeout time.Duration |
1973 | - // Concurrency limit for GET requests. The zero value (and negative |
1974 | - // values) result in a limit of GOMAXPROCS or 8, whichever is |
1975 | - // larger. Status code 503 is served for GET requests that would exceed |
1976 | - // the concurrency limit. |
1977 | - Concurrency int |
1978 | - // Logger is used for logging, if nil, no logging will happen. |
1979 | - Logger log.Logger |
1980 | - // Registry is used to register Prometheus metrics. If nil, no metrics |
1981 | - // registration will happen. |
1982 | - Registry prometheus.Registerer |
1983 | - // GroupFunc returns a list of alert groups. The alerts are grouped |
1984 | - // according to the current active configuration. Alerts returned are |
1985 | - // filtered by the arguments provided to the function. |
1986 | - GroupFunc func(func(*dispatch.Route) bool, func(*types.Alert, time.Time) bool) (dispatch.AlertGroups, map[model.Fingerprint][]string) |
1987 | -} |
1988 | - |
1989 | -func (o Options) validate() error { |
1990 | - if o.Alerts == nil { |
1991 | - return errors.New("mandatory field Alerts not set") |
1992 | - } |
1993 | - if o.Silences == nil { |
1994 | - return errors.New("mandatory field Silences not set") |
1995 | - } |
1996 | - if o.StatusFunc == nil { |
1997 | - return errors.New("mandatory field StatusFunc not set") |
1998 | - } |
1999 | - if o.GroupFunc == nil { |
2000 | - return errors.New("mandatory field GroupFunc not set") |
2001 | - } |
2002 | - return nil |
2003 | -} |
2004 | - |
2005 | -// New creates a new API object combining all API versions. Note that an Update |
2006 | -// call is also needed to get the APIs into an operational state. |
2007 | -func New(opts Options) (*API, error) { |
2008 | - if err := opts.validate(); err != nil { |
2009 | - return nil, fmt.Errorf("invalid API options: %s", err) |
2010 | - } |
2011 | - l := opts.Logger |
2012 | - if l == nil { |
2013 | - l = log.NewNopLogger() |
2014 | - } |
2015 | - concurrency := opts.Concurrency |
2016 | - if concurrency < 1 { |
2017 | - concurrency = runtime.GOMAXPROCS(0) |
2018 | - if concurrency < 8 { |
2019 | - concurrency = 8 |
2020 | - } |
2021 | - } |
2022 | - |
2023 | - v1 := apiv1.New( |
2024 | - opts.Alerts, |
2025 | - opts.Silences, |
2026 | - opts.StatusFunc, |
2027 | - opts.Peer, |
2028 | - log.With(l, "version", "v1"), |
2029 | - opts.Registry, |
2030 | - ) |
2031 | - |
2032 | - v2, err := apiv2.NewAPI( |
2033 | - opts.Alerts, |
2034 | - opts.GroupFunc, |
2035 | - opts.StatusFunc, |
2036 | - opts.Silences, |
2037 | - opts.Peer, |
2038 | - log.With(l, "version", "v2"), |
2039 | - opts.Registry, |
2040 | - ) |
2041 | - |
2042 | - if err != nil { |
2043 | - return nil, err |
2044 | - } |
2045 | - |
2046 | - // TODO(beorn7): For now, this hardcodes the method="get" label. Other |
2047 | - // methods should get the same instrumentation. |
2048 | - requestsInFlight := prometheus.NewGauge(prometheus.GaugeOpts{ |
2049 | - Name: "alertmanager_http_requests_in_flight", |
2050 | - Help: "Current number of HTTP requests being processed.", |
2051 | - ConstLabels: prometheus.Labels{"method": "get"}, |
2052 | - }) |
2053 | - concurrencyLimitExceeded := prometheus.NewCounter(prometheus.CounterOpts{ |
2054 | - Name: "alertmanager_http_concurrency_limit_exceeded_total", |
2055 | - Help: "Total number of times an HTTP request failed because the concurrency limit was reached.", |
2056 | - ConstLabels: prometheus.Labels{"method": "get"}, |
2057 | - }) |
2058 | - if opts.Registry != nil { |
2059 | - if err := opts.Registry.Register(requestsInFlight); err != nil { |
2060 | - return nil, err |
2061 | - } |
2062 | - if err := opts.Registry.Register(concurrencyLimitExceeded); err != nil { |
2063 | - return nil, err |
2064 | - } |
2065 | - } |
2066 | - |
2067 | - return &API{ |
2068 | - v1: v1, |
2069 | - v2: v2, |
2070 | - requestsInFlight: requestsInFlight, |
2071 | - concurrencyLimitExceeded: concurrencyLimitExceeded, |
2072 | - timeout: opts.Timeout, |
2073 | - inFlightSem: make(chan struct{}, concurrency), |
2074 | - }, nil |
2075 | -} |
2076 | - |
2077 | -// Register all APIs. It registers APIv1 with the provided router directly. As |
2078 | -// APIv2 works on the http.Handler level, this method also creates a new |
2079 | -// http.ServeMux and then uses it to register both the provided router (to |
2080 | -// handle "/") and APIv2 (to handle "<routePrefix>/api/v2"). The method returns |
2081 | -// the newly created http.ServeMux. If a timeout has been set on construction of |
2082 | -// API, it is enforced for all HTTP request going through this mux. The same is |
2083 | -// true for the concurrency limit, with the exception that it is only applied to |
2084 | -// GET requests. |
2085 | -func (api *API) Register(r *route.Router, routePrefix string) *http.ServeMux { |
2086 | - api.v1.Register(r.WithPrefix("/api/v1")) |
2087 | - |
2088 | - mux := http.NewServeMux() |
2089 | - mux.Handle("/", api.limitHandler(r)) |
2090 | - |
2091 | - apiPrefix := "" |
2092 | - if routePrefix != "/" { |
2093 | - apiPrefix = routePrefix |
2094 | - } |
2095 | - // TODO(beorn7): HTTP instrumentation is only in place for Router. Since |
2096 | - // /api/v2 works on the Handler level, it is currently not instrumented |
2097 | - // at all (with the exception of requestsInFlight, which is handled in |
2098 | - // limitHandler below). |
2099 | - mux.Handle( |
2100 | - apiPrefix+"/api/v2/", |
2101 | - api.limitHandler(http.StripPrefix(apiPrefix+"/api/v2", api.v2.Handler)), |
2102 | - ) |
2103 | - |
2104 | - return mux |
2105 | -} |
2106 | - |
2107 | -// Update config and resolve timeout of each API. APIv2 also needs |
2108 | -// setAlertStatus to be updated. |
2109 | -func (api *API) Update(cfg *config.Config, setAlertStatus func(model.LabelSet)) { |
2110 | - api.v1.Update(cfg) |
2111 | - api.v2.Update(cfg, setAlertStatus) |
2112 | -} |
2113 | - |
2114 | -func (api *API) limitHandler(h http.Handler) http.Handler { |
2115 | - concLimiter := http.HandlerFunc(func(rsp http.ResponseWriter, req *http.Request) { |
2116 | - if req.Method == http.MethodGet { // Only limit concurrency of GETs. |
2117 | - select { |
2118 | - case api.inFlightSem <- struct{}{}: // All good, carry on. |
2119 | - api.requestsInFlight.Inc() |
2120 | - defer func() { |
2121 | - <-api.inFlightSem |
2122 | - api.requestsInFlight.Dec() |
2123 | - }() |
2124 | - default: |
2125 | - api.concurrencyLimitExceeded.Inc() |
2126 | - http.Error(rsp, fmt.Sprintf( |
2127 | - "Limit of concurrent GET requests reached (%d), try again later.\n", cap(api.inFlightSem), |
2128 | - ), http.StatusServiceUnavailable) |
2129 | - return |
2130 | - } |
2131 | - } |
2132 | - h.ServeHTTP(rsp, req) |
2133 | - }) |
2134 | - if api.timeout <= 0 { |
2135 | - return concLimiter |
2136 | - } |
2137 | - return http.TimeoutHandler(concLimiter, api.timeout, fmt.Sprintf( |
2138 | - "Exceeded configured timeout of %v.\n", api.timeout, |
2139 | - )) |
2140 | -} |
2141 | diff --git a/api/metrics/metrics.go b/api/metrics/metrics.go |
2142 | deleted file mode 100644 |
2143 | index 483569a..0000000 |
2144 | --- a/api/metrics/metrics.go |
2145 | +++ /dev/null |
2146 | @@ -1,54 +0,0 @@ |
2147 | -// Copyright 2019 Prometheus Team |
2148 | -// Licensed under the Apache License, Version 2.0 (the "License"); |
2149 | -// you may not use this file except in compliance with the License. |
2150 | -// You may obtain a copy of the License at |
2151 | -// |
2152 | -// http://www.apache.org/licenses/LICENSE-2.0 |
2153 | -// |
2154 | -// Unless required by applicable law or agreed to in writing, software |
2155 | -// distributed under the License is distributed on an "AS IS" BASIS, |
2156 | -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
2157 | -// See the License for the specific language governing permissions and |
2158 | -// limitations under the License. |
2159 | - |
2160 | -package metrics |
2161 | - |
2162 | -import "github.com/prometheus/client_golang/prometheus" |
2163 | - |
2164 | -// Alerts stores metrics for alerts which are common across all API versions. |
2165 | -type Alerts struct { |
2166 | - firing prometheus.Counter |
2167 | - resolved prometheus.Counter |
2168 | - invalid prometheus.Counter |
2169 | -} |
2170 | - |
2171 | -// NewAlerts returns an *Alerts struct for the given API version. |
2172 | -func NewAlerts(version string, r prometheus.Registerer) *Alerts { |
2173 | - numReceivedAlerts := prometheus.NewCounterVec(prometheus.CounterOpts{ |
2174 | - Name: "alertmanager_alerts_received_total", |
2175 | - Help: "The total number of received alerts.", |
2176 | - ConstLabels: prometheus.Labels{"version": version}, |
2177 | - }, []string{"status"}) |
2178 | - numInvalidAlerts := prometheus.NewCounter(prometheus.CounterOpts{ |
2179 | - Name: "alertmanager_alerts_invalid_total", |
2180 | - Help: "The total number of received alerts that were invalid.", |
2181 | - ConstLabels: prometheus.Labels{"version": version}, |
2182 | - }) |
2183 | - if r != nil { |
2184 | - r.MustRegister(numReceivedAlerts, numInvalidAlerts) |
2185 | - } |
2186 | - return &Alerts{ |
2187 | - firing: numReceivedAlerts.WithLabelValues("firing"), |
2188 | - resolved: numReceivedAlerts.WithLabelValues("resolved"), |
2189 | - invalid: numInvalidAlerts, |
2190 | - } |
2191 | -} |
2192 | - |
2193 | -// Firing returns a counter of firing alerts. |
2194 | -func (a *Alerts) Firing() prometheus.Counter { return a.firing } |
2195 | - |
2196 | -// Resolved returns a counter of resolved alerts. |
2197 | -func (a *Alerts) Resolved() prometheus.Counter { return a.resolved } |
2198 | - |
2199 | -// Invalid returns a counter of invalid alerts. |
2200 | -func (a *Alerts) Invalid() prometheus.Counter { return a.invalid } |
2201 | diff --git a/api/v1/api.go b/api/v1/api.go |
2202 | deleted file mode 100644 |
2203 | index 3a14664..0000000 |
2204 | --- a/api/v1/api.go |
2205 | +++ /dev/null |
2206 | @@ -1,797 +0,0 @@ |
2207 | -// Copyright 2015 Prometheus Team |
2208 | -// Licensed under the Apache License, Version 2.0 (the "License"); |
2209 | -// you may not use this file except in compliance with the License. |
2210 | -// You may obtain a copy of the License at |
2211 | -// |
2212 | -// http://www.apache.org/licenses/LICENSE-2.0 |
2213 | -// |
2214 | -// Unless required by applicable law or agreed to in writing, software |
2215 | -// distributed under the License is distributed on an "AS IS" BASIS, |
2216 | -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
2217 | -// See the License for the specific language governing permissions and |
2218 | -// limitations under the License. |
2219 | - |
2220 | -package v1 |
2221 | - |
2222 | -import ( |
2223 | - "encoding/json" |
2224 | - "errors" |
2225 | - "fmt" |
2226 | - "net/http" |
2227 | - "regexp" |
2228 | - "sort" |
2229 | - "sync" |
2230 | - "time" |
2231 | - |
2232 | - "github.com/go-kit/kit/log" |
2233 | - "github.com/go-kit/kit/log/level" |
2234 | - "github.com/prometheus/client_golang/prometheus" |
2235 | - "github.com/prometheus/common/model" |
2236 | - "github.com/prometheus/common/route" |
2237 | - "github.com/prometheus/common/version" |
2238 | - |
2239 | - "github.com/prometheus/alertmanager/api/metrics" |
2240 | - "github.com/prometheus/alertmanager/cluster" |
2241 | - "github.com/prometheus/alertmanager/config" |
2242 | - "github.com/prometheus/alertmanager/dispatch" |
2243 | - "github.com/prometheus/alertmanager/pkg/labels" |
2244 | - "github.com/prometheus/alertmanager/provider" |
2245 | - "github.com/prometheus/alertmanager/silence" |
2246 | - "github.com/prometheus/alertmanager/silence/silencepb" |
2247 | - "github.com/prometheus/alertmanager/types" |
2248 | -) |
2249 | - |
2250 | -var corsHeaders = map[string]string{ |
2251 | - "Access-Control-Allow-Headers": "Accept, Authorization, Content-Type, Origin", |
2252 | - "Access-Control-Allow-Methods": "GET, POST, DELETE, OPTIONS", |
2253 | - "Access-Control-Allow-Origin": "*", |
2254 | - "Access-Control-Expose-Headers": "Date", |
2255 | - "Cache-Control": "no-cache, no-store, must-revalidate", |
2256 | -} |
2257 | - |
2258 | -// Alert is the API representation of an alert, which is a regular alert |
2259 | -// annotated with silencing and inhibition info. |
2260 | -type Alert struct { |
2261 | - *model.Alert |
2262 | - Status types.AlertStatus `json:"status"` |
2263 | - Receivers []string `json:"receivers"` |
2264 | - Fingerprint string `json:"fingerprint"` |
2265 | -} |
2266 | - |
2267 | -// Enables cross-site script calls. |
2268 | -func setCORS(w http.ResponseWriter) { |
2269 | - for h, v := range corsHeaders { |
2270 | - w.Header().Set(h, v) |
2271 | - } |
2272 | -} |
2273 | - |
2274 | -// API provides registration of handlers for API routes. |
2275 | -type API struct { |
2276 | - alerts provider.Alerts |
2277 | - silences *silence.Silences |
2278 | - config *config.Config |
2279 | - route *dispatch.Route |
2280 | - uptime time.Time |
2281 | - peer *cluster.Peer |
2282 | - logger log.Logger |
2283 | - m *metrics.Alerts |
2284 | - |
2285 | - getAlertStatus getAlertStatusFn |
2286 | - |
2287 | - mtx sync.RWMutex |
2288 | -} |
2289 | - |
2290 | -type getAlertStatusFn func(model.Fingerprint) types.AlertStatus |
2291 | - |
2292 | -// New returns a new API. |
2293 | -func New( |
2294 | - alerts provider.Alerts, |
2295 | - silences *silence.Silences, |
2296 | - sf getAlertStatusFn, |
2297 | - peer *cluster.Peer, |
2298 | - l log.Logger, |
2299 | - r prometheus.Registerer, |
2300 | -) *API { |
2301 | - if l == nil { |
2302 | - l = log.NewNopLogger() |
2303 | - } |
2304 | - |
2305 | - return &API{ |
2306 | - alerts: alerts, |
2307 | - silences: silences, |
2308 | - getAlertStatus: sf, |
2309 | - uptime: time.Now(), |
2310 | - peer: peer, |
2311 | - logger: l, |
2312 | - m: metrics.NewAlerts("v1", r), |
2313 | - } |
2314 | -} |
2315 | - |
2316 | -// Register registers the API handlers under their correct routes |
2317 | -// in the given router. |
2318 | -func (api *API) Register(r *route.Router) { |
2319 | - wrap := func(f http.HandlerFunc) http.HandlerFunc { |
2320 | - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
2321 | - setCORS(w) |
2322 | - f(w, r) |
2323 | - }) |
2324 | - } |
2325 | - |
2326 | - r.Options("/*path", wrap(func(w http.ResponseWriter, r *http.Request) {})) |
2327 | - |
2328 | - r.Get("/status", wrap(api.status)) |
2329 | - r.Get("/receivers", wrap(api.receivers)) |
2330 | - |
2331 | - r.Get("/alerts", wrap(api.listAlerts)) |
2332 | - r.Post("/alerts", wrap(api.addAlerts)) |
2333 | - |
2334 | - r.Get("/silences", wrap(api.listSilences)) |
2335 | - r.Post("/silences", wrap(api.setSilence)) |
2336 | - r.Get("/silence/:sid", wrap(api.getSilence)) |
2337 | - r.Del("/silence/:sid", wrap(api.delSilence)) |
2338 | -} |
2339 | - |
2340 | -// Update sets the configuration string to a new value. |
2341 | -func (api *API) Update(cfg *config.Config) { |
2342 | - api.mtx.Lock() |
2343 | - defer api.mtx.Unlock() |
2344 | - |
2345 | - api.config = cfg |
2346 | - api.route = dispatch.NewRoute(cfg.Route, nil) |
2347 | -} |
2348 | - |
2349 | -type errorType string |
2350 | - |
2351 | -const ( |
2352 | - errorInternal errorType = "server_error" |
2353 | - errorBadData errorType = "bad_data" |
2354 | -) |
2355 | - |
2356 | -type apiError struct { |
2357 | - typ errorType |
2358 | - err error |
2359 | -} |
2360 | - |
2361 | -func (e *apiError) Error() string { |
2362 | - return fmt.Sprintf("%s: %s", e.typ, e.err) |
2363 | -} |
2364 | - |
2365 | -func (api *API) receivers(w http.ResponseWriter, req *http.Request) { |
2366 | - api.mtx.RLock() |
2367 | - defer api.mtx.RUnlock() |
2368 | - |
2369 | - receivers := make([]string, 0, len(api.config.Receivers)) |
2370 | - for _, r := range api.config.Receivers { |
2371 | - receivers = append(receivers, r.Name) |
2372 | - } |
2373 | - |
2374 | - api.respond(w, receivers) |
2375 | -} |
2376 | - |
2377 | -func (api *API) status(w http.ResponseWriter, req *http.Request) { |
2378 | - api.mtx.RLock() |
2379 | - |
2380 | - var status = struct { |
2381 | - ConfigYAML string `json:"configYAML"` |
2382 | - ConfigJSON *config.Config `json:"configJSON"` |
2383 | - VersionInfo map[string]string `json:"versionInfo"` |
2384 | - Uptime time.Time `json:"uptime"` |
2385 | - ClusterStatus *clusterStatus `json:"clusterStatus"` |
2386 | - }{ |
2387 | - ConfigYAML: api.config.String(), |
2388 | - ConfigJSON: api.config, |
2389 | - VersionInfo: map[string]string{ |
2390 | - "version": version.Version, |
2391 | - "revision": version.Revision, |
2392 | - "branch": version.Branch, |
2393 | - "buildUser": version.BuildUser, |
2394 | - "buildDate": version.BuildDate, |
2395 | - "goVersion": version.GoVersion, |
2396 | - }, |
2397 | - Uptime: api.uptime, |
2398 | - ClusterStatus: getClusterStatus(api.peer), |
2399 | - } |
2400 | - |
2401 | - api.mtx.RUnlock() |
2402 | - |
2403 | - api.respond(w, status) |
2404 | -} |
2405 | - |
2406 | -type peerStatus struct { |
2407 | - Name string `json:"name"` |
2408 | - Address string `json:"address"` |
2409 | -} |
2410 | - |
2411 | -type clusterStatus struct { |
2412 | - Name string `json:"name"` |
2413 | - Status string `json:"status"` |
2414 | - Peers []peerStatus `json:"peers"` |
2415 | -} |
2416 | - |
2417 | -func getClusterStatus(p *cluster.Peer) *clusterStatus { |
2418 | - if p == nil { |
2419 | - return nil |
2420 | - } |
2421 | - s := &clusterStatus{Name: p.Name(), Status: p.Status()} |
2422 | - |
2423 | - for _, n := range p.Peers() { |
2424 | - s.Peers = append(s.Peers, peerStatus{ |
2425 | - Name: n.Name, |
2426 | - Address: n.Address(), |
2427 | - }) |
2428 | - } |
2429 | - return s |
2430 | -} |
2431 | - |
2432 | -func (api *API) listAlerts(w http.ResponseWriter, r *http.Request) { |
2433 | - var ( |
2434 | - err error |
2435 | - receiverFilter *regexp.Regexp |
2436 | - // Initialize result slice to prevent api returning `null` when there |
2437 | - // are no alerts present |
2438 | - res = []*Alert{} |
2439 | - matchers = []*labels.Matcher{} |
2440 | - ctx = r.Context() |
2441 | - |
2442 | - showActive, showInhibited bool |
2443 | - showSilenced, showUnprocessed bool |
2444 | - ) |
2445 | - |
2446 | - getBoolParam := func(name string) (bool, error) { |
2447 | - v := r.FormValue(name) |
2448 | - if v == "" { |
2449 | - return true, nil |
2450 | - } |
2451 | - if v == "false" { |
2452 | - return false, nil |
2453 | - } |
2454 | - if v != "true" { |
2455 | - err := fmt.Errorf("parameter %q can either be 'true' or 'false', not %q", name, v) |
2456 | - api.respondError(w, apiError{ |
2457 | - typ: errorBadData, |
2458 | - err: err, |
2459 | - }, nil) |
2460 | - return false, err |
2461 | - } |
2462 | - return true, nil |
2463 | - } |
2464 | - |
2465 | - if filter := r.FormValue("filter"); filter != "" { |
2466 | - matchers, err = labels.ParseMatchers(filter) |
2467 | - if err != nil { |
2468 | - api.respondError(w, apiError{ |
2469 | - typ: errorBadData, |
2470 | - err: err, |
2471 | - }, nil) |
2472 | - return |
2473 | - } |
2474 | - } |
2475 | - |
2476 | - showActive, err = getBoolParam("active") |
2477 | - if err != nil { |
2478 | - return |
2479 | - } |
2480 | - |
2481 | - showSilenced, err = getBoolParam("silenced") |
2482 | - if err != nil { |
2483 | - return |
2484 | - } |
2485 | - |
2486 | - showInhibited, err = getBoolParam("inhibited") |
2487 | - if err != nil { |
2488 | - return |
2489 | - } |
2490 | - |
2491 | - showUnprocessed, err = getBoolParam("unprocessed") |
2492 | - if err != nil { |
2493 | - return |
2494 | - } |
2495 | - |
2496 | - if receiverParam := r.FormValue("receiver"); receiverParam != "" { |
2497 | - receiverFilter, err = regexp.Compile("^(?:" + receiverParam + ")$") |
2498 | - if err != nil { |
2499 | - api.respondError(w, apiError{ |
2500 | - typ: errorBadData, |
2501 | - err: fmt.Errorf( |
2502 | - "failed to parse receiver param: %s", |
2503 | - receiverParam, |
2504 | - ), |
2505 | - }, nil) |
2506 | - return |
2507 | - } |
2508 | - } |
2509 | - |
2510 | - alerts := api.alerts.GetPending() |
2511 | - defer alerts.Close() |
2512 | - |
2513 | - api.mtx.RLock() |
2514 | - for a := range alerts.Next() { |
2515 | - if err = alerts.Err(); err != nil { |
2516 | - break |
2517 | - } |
2518 | - if err = ctx.Err(); err != nil { |
2519 | - break |
2520 | - } |
2521 | - |
2522 | - routes := api.route.Match(a.Labels) |
2523 | - receivers := make([]string, 0, len(routes)) |
2524 | - for _, r := range routes { |
2525 | - receivers = append(receivers, r.RouteOpts.Receiver) |
2526 | - } |
2527 | - |
2528 | - if receiverFilter != nil && !receiversMatchFilter(receivers, receiverFilter) { |
2529 | - continue |
2530 | - } |
2531 | - |
2532 | - if !alertMatchesFilterLabels(&a.Alert, matchers) { |
2533 | - continue |
2534 | - } |
2535 | - |
2536 | - // Continue if the alert is resolved. |
2537 | - if !a.Alert.EndsAt.IsZero() && a.Alert.EndsAt.Before(time.Now()) { |
2538 | - continue |
2539 | - } |
2540 | - |
2541 | - status := api.getAlertStatus(a.Fingerprint()) |
2542 | - |
2543 | - if !showActive && status.State == types.AlertStateActive { |
2544 | - continue |
2545 | - } |
2546 | - |
2547 | - if !showUnprocessed && status.State == types.AlertStateUnprocessed { |
2548 | - continue |
2549 | - } |
2550 | - |
2551 | - if !showSilenced && len(status.SilencedBy) != 0 { |
2552 | - continue |
2553 | - } |
2554 | - |
2555 | - if !showInhibited && len(status.InhibitedBy) != 0 { |
2556 | - continue |
2557 | - } |
2558 | - |
2559 | - alert := &Alert{ |
2560 | - Alert: &a.Alert, |
2561 | - Status: status, |
2562 | - Receivers: receivers, |
2563 | - Fingerprint: a.Fingerprint().String(), |
2564 | - } |
2565 | - |
2566 | - res = append(res, alert) |
2567 | - } |
2568 | - api.mtx.RUnlock() |
2569 | - |
2570 | - if err != nil { |
2571 | - api.respondError(w, apiError{ |
2572 | - typ: errorInternal, |
2573 | - err: err, |
2574 | - }, nil) |
2575 | - return |
2576 | - } |
2577 | - sort.Slice(res, func(i, j int) bool { |
2578 | - return res[i].Fingerprint < res[j].Fingerprint |
2579 | - }) |
2580 | - api.respond(w, res) |
2581 | -} |
2582 | - |
2583 | -func receiversMatchFilter(receivers []string, filter *regexp.Regexp) bool { |
2584 | - for _, r := range receivers { |
2585 | - if filter.MatchString(r) { |
2586 | - return true |
2587 | - } |
2588 | - } |
2589 | - |
2590 | - return false |
2591 | -} |
2592 | - |
2593 | -func alertMatchesFilterLabels(a *model.Alert, matchers []*labels.Matcher) bool { |
2594 | - sms := make(map[string]string) |
2595 | - for name, value := range a.Labels { |
2596 | - sms[string(name)] = string(value) |
2597 | - } |
2598 | - return matchFilterLabels(matchers, sms) |
2599 | -} |
2600 | - |
2601 | -func (api *API) addAlerts(w http.ResponseWriter, r *http.Request) { |
2602 | - var alerts []*types.Alert |
2603 | - if err := api.receive(r, &alerts); err != nil { |
2604 | - api.respondError(w, apiError{ |
2605 | - typ: errorBadData, |
2606 | - err: err, |
2607 | - }, nil) |
2608 | - return |
2609 | - } |
2610 | - |
2611 | - api.insertAlerts(w, r, alerts...) |
2612 | -} |
2613 | - |
2614 | -func (api *API) insertAlerts(w http.ResponseWriter, r *http.Request, alerts ...*types.Alert) { |
2615 | - now := time.Now() |
2616 | - |
2617 | - api.mtx.RLock() |
2618 | - resolveTimeout := time.Duration(api.config.Global.ResolveTimeout) |
2619 | - api.mtx.RUnlock() |
2620 | - |
2621 | - for _, alert := range alerts { |
2622 | - alert.UpdatedAt = now |
2623 | - |
2624 | - // Ensure StartsAt is set. |
2625 | - if alert.StartsAt.IsZero() { |
2626 | - if alert.EndsAt.IsZero() { |
2627 | - alert.StartsAt = now |
2628 | - } else { |
2629 | - alert.StartsAt = alert.EndsAt |
2630 | - } |
2631 | - } |
2632 | - // If no end time is defined, set a timeout after which an alert |
2633 | - // is marked resolved if it is not updated. |
2634 | - if alert.EndsAt.IsZero() { |
2635 | - alert.Timeout = true |
2636 | - alert.EndsAt = now.Add(resolveTimeout) |
2637 | - } |
2638 | - if alert.EndsAt.After(time.Now()) { |
2639 | - api.m.Firing().Inc() |
2640 | - } else { |
2641 | - api.m.Resolved().Inc() |
2642 | - } |
2643 | - } |
2644 | - |
2645 | - // Make a best effort to insert all alerts that are valid. |
2646 | - var ( |
2647 | - validAlerts = make([]*types.Alert, 0, len(alerts)) |
2648 | - validationErrs = &types.MultiError{} |
2649 | - ) |
2650 | - for _, a := range alerts { |
2651 | - removeEmptyLabels(a.Labels) |
2652 | - |
2653 | - if err := a.Validate(); err != nil { |
2654 | - validationErrs.Add(err) |
2655 | - api.m.Invalid().Inc() |
2656 | - continue |
2657 | - } |
2658 | - validAlerts = append(validAlerts, a) |
2659 | - } |
2660 | - if err := api.alerts.Put(validAlerts...); err != nil { |
2661 | - api.respondError(w, apiError{ |
2662 | - typ: errorInternal, |
2663 | - err: err, |
2664 | - }, nil) |
2665 | - return |
2666 | - } |
2667 | - |
2668 | - if validationErrs.Len() > 0 { |
2669 | - api.respondError(w, apiError{ |
2670 | - typ: errorBadData, |
2671 | - err: validationErrs, |
2672 | - }, nil) |
2673 | - return |
2674 | - } |
2675 | - |
2676 | - api.respond(w, nil) |
2677 | -} |
2678 | - |
2679 | -func removeEmptyLabels(ls model.LabelSet) { |
2680 | - for k, v := range ls { |
2681 | - if string(v) == "" { |
2682 | - delete(ls, k) |
2683 | - } |
2684 | - } |
2685 | -} |
2686 | - |
2687 | -func (api *API) setSilence(w http.ResponseWriter, r *http.Request) { |
2688 | - var sil types.Silence |
2689 | - if err := api.receive(r, &sil); err != nil { |
2690 | - api.respondError(w, apiError{ |
2691 | - typ: errorBadData, |
2692 | - err: err, |
2693 | - }, nil) |
2694 | - return |
2695 | - } |
2696 | - |
2697 | - // This is an API only validation, it cannot be done internally |
2698 | - // because the expired silence is semantically important. |
2699 | - // But one should not be able to create expired silences, that |
2700 | - // won't have any use. |
2701 | - if sil.Expired() { |
2702 | - api.respondError(w, apiError{ |
2703 | - typ: errorBadData, |
2704 | - err: errors.New("start time must not be equal to end time"), |
2705 | - }, nil) |
2706 | - return |
2707 | - } |
2708 | - |
2709 | - if sil.EndsAt.Before(time.Now()) { |
2710 | - api.respondError(w, apiError{ |
2711 | - typ: errorBadData, |
2712 | - err: errors.New("end time can't be in the past"), |
2713 | - }, nil) |
2714 | - return |
2715 | - } |
2716 | - |
2717 | - psil, err := silenceToProto(&sil) |
2718 | - if err != nil { |
2719 | - api.respondError(w, apiError{ |
2720 | - typ: errorBadData, |
2721 | - err: err, |
2722 | - }, nil) |
2723 | - return |
2724 | - } |
2725 | - |
2726 | - sid, err := api.silences.Set(psil) |
2727 | - if err != nil { |
2728 | - api.respondError(w, apiError{ |
2729 | - typ: errorBadData, |
2730 | - err: err, |
2731 | - }, nil) |
2732 | - return |
2733 | - } |
2734 | - |
2735 | - api.respond(w, struct { |
2736 | - SilenceID string `json:"silenceId"` |
2737 | - }{ |
2738 | - SilenceID: sid, |
2739 | - }) |
2740 | -} |
2741 | - |
2742 | -func (api *API) getSilence(w http.ResponseWriter, r *http.Request) { |
2743 | - sid := route.Param(r.Context(), "sid") |
2744 | - |
2745 | - sils, _, err := api.silences.Query(silence.QIDs(sid)) |
2746 | - if err != nil || len(sils) == 0 { |
2747 | - http.Error(w, fmt.Sprint("Error getting silence: ", err), http.StatusNotFound) |
2748 | - return |
2749 | - } |
2750 | - sil, err := silenceFromProto(sils[0]) |
2751 | - if err != nil { |
2752 | - api.respondError(w, apiError{ |
2753 | - typ: errorInternal, |
2754 | - err: err, |
2755 | - }, nil) |
2756 | - return |
2757 | - } |
2758 | - |
2759 | - api.respond(w, sil) |
2760 | -} |
2761 | - |
2762 | -func (api *API) delSilence(w http.ResponseWriter, r *http.Request) { |
2763 | - sid := route.Param(r.Context(), "sid") |
2764 | - |
2765 | - if err := api.silences.Expire(sid); err != nil { |
2766 | - api.respondError(w, apiError{ |
2767 | - typ: errorBadData, |
2768 | - err: err, |
2769 | - }, nil) |
2770 | - return |
2771 | - } |
2772 | - api.respond(w, nil) |
2773 | -} |
2774 | - |
2775 | -func (api *API) listSilences(w http.ResponseWriter, r *http.Request) { |
2776 | - psils, _, err := api.silences.Query() |
2777 | - if err != nil { |
2778 | - api.respondError(w, apiError{ |
2779 | - typ: errorInternal, |
2780 | - err: err, |
2781 | - }, nil) |
2782 | - return |
2783 | - } |
2784 | - |
2785 | - matchers := []*labels.Matcher{} |
2786 | - if filter := r.FormValue("filter"); filter != "" { |
2787 | - matchers, err = labels.ParseMatchers(filter) |
2788 | - if err != nil { |
2789 | - api.respondError(w, apiError{ |
2790 | - typ: errorBadData, |
2791 | - err: err, |
2792 | - }, nil) |
2793 | - return |
2794 | - } |
2795 | - } |
2796 | - |
2797 | - sils := []*types.Silence{} |
2798 | - for _, ps := range psils { |
2799 | - s, err := silenceFromProto(ps) |
2800 | - if err != nil { |
2801 | - api.respondError(w, apiError{ |
2802 | - typ: errorInternal, |
2803 | - err: err, |
2804 | - }, nil) |
2805 | - return |
2806 | - } |
2807 | - |
2808 | - if !silenceMatchesFilterLabels(s, matchers) { |
2809 | - continue |
2810 | - } |
2811 | - sils = append(sils, s) |
2812 | - } |
2813 | - |
2814 | - var active, pending, expired []*types.Silence |
2815 | - |
2816 | - for _, s := range sils { |
2817 | - switch s.Status.State { |
2818 | - case types.SilenceStateActive: |
2819 | - active = append(active, s) |
2820 | - case types.SilenceStatePending: |
2821 | - pending = append(pending, s) |
2822 | - case types.SilenceStateExpired: |
2823 | - expired = append(expired, s) |
2824 | - } |
2825 | - } |
2826 | - |
2827 | - sort.Slice(active, func(i int, j int) bool { |
2828 | - return active[i].EndsAt.Before(active[j].EndsAt) |
2829 | - }) |
2830 | - sort.Slice(pending, func(i int, j int) bool { |
2831 | - return pending[i].StartsAt.Before(pending[j].EndsAt) |
2832 | - }) |
2833 | - sort.Slice(expired, func(i int, j int) bool { |
2834 | - return expired[i].EndsAt.After(expired[j].EndsAt) |
2835 | - }) |
2836 | - |
2837 | - // Initialize silences explicitly to an empty list (instead of nil) |
2838 | - // So that it does not get converted to "null" in JSON. |
2839 | - silences := []*types.Silence{} |
2840 | - silences = append(silences, active...) |
2841 | - silences = append(silences, pending...) |
2842 | - silences = append(silences, expired...) |
2843 | - |
2844 | - api.respond(w, silences) |
2845 | -} |
2846 | - |
2847 | -func silenceMatchesFilterLabels(s *types.Silence, matchers []*labels.Matcher) bool { |
2848 | - sms := make(map[string]string) |
2849 | - for _, m := range s.Matchers { |
2850 | - sms[m.Name] = m.Value |
2851 | - } |
2852 | - |
2853 | - return matchFilterLabels(matchers, sms) |
2854 | -} |
2855 | - |
2856 | -func matchFilterLabels(matchers []*labels.Matcher, sms map[string]string) bool { |
2857 | - for _, m := range matchers { |
2858 | - v, prs := sms[m.Name] |
2859 | - switch m.Type { |
2860 | - case labels.MatchNotRegexp, labels.MatchNotEqual: |
2861 | - if string(m.Value) == "" && prs { |
2862 | - continue |
2863 | - } |
2864 | - if !m.Matches(string(v)) { |
2865 | - return false |
2866 | - } |
2867 | - default: |
2868 | - if string(m.Value) == "" && !prs { |
2869 | - continue |
2870 | - } |
2871 | - if !prs || !m.Matches(string(v)) { |
2872 | - return false |
2873 | - } |
2874 | - } |
2875 | - } |
2876 | - |
2877 | - return true |
2878 | -} |
2879 | - |
2880 | -func silenceToProto(s *types.Silence) (*silencepb.Silence, error) { |
2881 | - sil := &silencepb.Silence{ |
2882 | - Id: s.ID, |
2883 | - StartsAt: s.StartsAt, |
2884 | - EndsAt: s.EndsAt, |
2885 | - UpdatedAt: s.UpdatedAt, |
2886 | - Comment: s.Comment, |
2887 | - CreatedBy: s.CreatedBy, |
2888 | - } |
2889 | - for _, m := range s.Matchers { |
2890 | - matcher := &silencepb.Matcher{ |
2891 | - Name: m.Name, |
2892 | - Pattern: m.Value, |
2893 | - Type: silencepb.Matcher_EQUAL, |
2894 | - } |
2895 | - if m.IsRegex { |
2896 | - matcher.Type = silencepb.Matcher_REGEXP |
2897 | - } |
2898 | - sil.Matchers = append(sil.Matchers, matcher) |
2899 | - } |
2900 | - return sil, nil |
2901 | -} |
2902 | - |
2903 | -func silenceFromProto(s *silencepb.Silence) (*types.Silence, error) { |
2904 | - sil := &types.Silence{ |
2905 | - ID: s.Id, |
2906 | - StartsAt: s.StartsAt, |
2907 | - EndsAt: s.EndsAt, |
2908 | - UpdatedAt: s.UpdatedAt, |
2909 | - Status: types.SilenceStatus{ |
2910 | - State: types.CalcSilenceState(s.StartsAt, s.EndsAt), |
2911 | - }, |
2912 | - Comment: s.Comment, |
2913 | - CreatedBy: s.CreatedBy, |
2914 | - } |
2915 | - for _, m := range s.Matchers { |
2916 | - matcher := &types.Matcher{ |
2917 | - Name: m.Name, |
2918 | - Value: m.Pattern, |
2919 | - } |
2920 | - switch m.Type { |
2921 | - case silencepb.Matcher_EQUAL: |
2922 | - case silencepb.Matcher_REGEXP: |
2923 | - matcher.IsRegex = true |
2924 | - default: |
2925 | - return nil, fmt.Errorf("unknown matcher type") |
2926 | - } |
2927 | - sil.Matchers = append(sil.Matchers, matcher) |
2928 | - } |
2929 | - |
2930 | - return sil, nil |
2931 | -} |
2932 | - |
2933 | -type status string |
2934 | - |
2935 | -const ( |
2936 | - statusSuccess status = "success" |
2937 | - statusError status = "error" |
2938 | -) |
2939 | - |
2940 | -type response struct { |
2941 | - Status status `json:"status"` |
2942 | - Data interface{} `json:"data,omitempty"` |
2943 | - ErrorType errorType `json:"errorType,omitempty"` |
2944 | - Error string `json:"error,omitempty"` |
2945 | -} |
2946 | - |
2947 | -func (api *API) respond(w http.ResponseWriter, data interface{}) { |
2948 | - w.Header().Set("Content-Type", "application/json") |
2949 | - w.WriteHeader(200) |
2950 | - |
2951 | - b, err := json.Marshal(&response{ |
2952 | - Status: statusSuccess, |
2953 | - Data: data, |
2954 | - }) |
2955 | - if err != nil { |
2956 | - level.Error(api.logger).Log("msg", "Error marshaling JSON", "err", err) |
2957 | - return |
2958 | - } |
2959 | - |
2960 | - if _, err := w.Write(b); err != nil { |
2961 | - level.Error(api.logger).Log("msg", "failed to write data to connection", "err", err) |
2962 | - } |
2963 | -} |
2964 | - |
2965 | -func (api *API) respondError(w http.ResponseWriter, apiErr apiError, data interface{}) { |
2966 | - w.Header().Set("Content-Type", "application/json") |
2967 | - |
2968 | - switch apiErr.typ { |
2969 | - case errorBadData: |
2970 | - w.WriteHeader(http.StatusBadRequest) |
2971 | - case errorInternal: |
2972 | - w.WriteHeader(http.StatusInternalServerError) |
2973 | - default: |
2974 | - panic(fmt.Sprintf("unknown error type %q", apiErr.Error())) |
2975 | - } |
2976 | - |
2977 | - b, err := json.Marshal(&response{ |
2978 | - Status: statusError, |
2979 | - ErrorType: apiErr.typ, |
2980 | - Error: apiErr.err.Error(), |
2981 | - Data: data, |
2982 | - }) |
2983 | - if err != nil { |
2984 | - return |
2985 | - } |
2986 | - level.Error(api.logger).Log("msg", "API error", "err", apiErr.Error()) |
2987 | - |
2988 | - if _, err := w.Write(b); err != nil { |
2989 | - level.Error(api.logger).Log("msg", "failed to write data to connection", "err", err) |
2990 | - } |
2991 | -} |
2992 | - |
2993 | -func (api *API) receive(r *http.Request, v interface{}) error { |
2994 | - dec := json.NewDecoder(r.Body) |
2995 | - defer r.Body.Close() |
2996 | - |
2997 | - err := dec.Decode(v) |
2998 | - if err != nil { |
2999 | - level.Debug(api.logger).Log("msg", "Decoding request failed", "err", err) |
3000 | - return err |
3001 | - } |
3002 | - return nil |
3003 | -} |
3004 | diff --git a/api/v1/api_test.go b/api/v1/api_test.go |
3005 | deleted file mode 100644 |
3006 | index d25f362..0000000 |
3007 | --- a/api/v1/api_test.go |
3008 | +++ /dev/null |
3009 | @@ -1,581 +0,0 @@ |
3010 | -// Copyright 2018 Prometheus Team |
3011 | -// Licensed under the Apache License, Version 2.0 (the "License"); |
3012 | -// you may not use this file except in compliance with the License. |
3013 | -// You may obtain a copy of the License at |
3014 | -// |
3015 | -// http://www.apache.org/licenses/LICENSE-2.0 |
3016 | -// |
3017 | -// Unless required by applicable law or agreed to in writing, software |
3018 | -// distributed under the License is distributed on an "AS IS" BASIS, |
3019 | -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
3020 | -// See the License for the specific language governing permissions and |
3021 | -// limitations under the License. |
3022 | - |
3023 | -package v1 |
3024 | - |
3025 | -import ( |
3026 | - "bytes" |
3027 | - "encoding/json" |
3028 | - "errors" |
3029 | - "fmt" |
3030 | - "io/ioutil" |
3031 | - "net/http" |
3032 | - "net/http/httptest" |
3033 | - "regexp" |
3034 | - "testing" |
3035 | - "time" |
3036 | - |
3037 | - "github.com/prometheus/common/model" |
3038 | - "github.com/stretchr/testify/require" |
3039 | - |
3040 | - "github.com/prometheus/alertmanager/config" |
3041 | - "github.com/prometheus/alertmanager/dispatch" |
3042 | - "github.com/prometheus/alertmanager/pkg/labels" |
3043 | - "github.com/prometheus/alertmanager/provider" |
3044 | - "github.com/prometheus/alertmanager/types" |
3045 | -) |
3046 | - |
3047 | -// fakeAlerts is a struct implementing the provider.Alerts interface for tests. |
3048 | -type fakeAlerts struct { |
3049 | - fps map[model.Fingerprint]int |
3050 | - alerts []*types.Alert |
3051 | - err error |
3052 | -} |
3053 | - |
3054 | -func newFakeAlerts(alerts []*types.Alert, withErr bool) *fakeAlerts { |
3055 | - fps := make(map[model.Fingerprint]int) |
3056 | - for i, a := range alerts { |
3057 | - fps[a.Fingerprint()] = i |
3058 | - } |
3059 | - f := &fakeAlerts{ |
3060 | - alerts: alerts, |
3061 | - fps: fps, |
3062 | - } |
3063 | - if withErr { |
3064 | - f.err = errors.New("error occurred") |
3065 | - } |
3066 | - return f |
3067 | -} |
3068 | - |
3069 | -func (f *fakeAlerts) Subscribe() provider.AlertIterator { return nil } |
3070 | -func (f *fakeAlerts) Get(model.Fingerprint) (*types.Alert, error) { return nil, nil } |
3071 | -func (f *fakeAlerts) Put(alerts ...*types.Alert) error { |
3072 | - return f.err |
3073 | -} |
3074 | -func (f *fakeAlerts) GetPending() provider.AlertIterator { |
3075 | - ch := make(chan *types.Alert) |
3076 | - done := make(chan struct{}) |
3077 | - go func() { |
3078 | - defer close(ch) |
3079 | - for _, a := range f.alerts { |
3080 | - ch <- a |
3081 | - } |
3082 | - }() |
3083 | - return provider.NewAlertIterator(ch, done, f.err) |
3084 | -} |
3085 | - |
3086 | -func newGetAlertStatus(f *fakeAlerts) func(model.Fingerprint) types.AlertStatus { |
3087 | - return func(fp model.Fingerprint) types.AlertStatus { |
3088 | - status := types.AlertStatus{SilencedBy: []string{}, InhibitedBy: []string{}} |
3089 | - |
3090 | - i, ok := f.fps[fp] |
3091 | - if !ok { |
3092 | - return status |
3093 | - } |
3094 | - alert := f.alerts[i] |
3095 | - switch alert.Labels["state"] { |
3096 | - case "active": |
3097 | - status.State = types.AlertStateActive |
3098 | - case "unprocessed": |
3099 | - status.State = types.AlertStateUnprocessed |
3100 | - case "suppressed": |
3101 | - status.State = types.AlertStateSuppressed |
3102 | - } |
3103 | - if alert.Labels["silenced_by"] != "" { |
3104 | - status.SilencedBy = append(status.SilencedBy, string(alert.Labels["silenced_by"])) |
3105 | - } |
3106 | - if alert.Labels["inhibited_by"] != "" { |
3107 | - status.InhibitedBy = append(status.InhibitedBy, string(alert.Labels["inhibited_by"])) |
3108 | - } |
3109 | - return status |
3110 | - } |
3111 | -} |
3112 | - |
3113 | -func TestAddAlerts(t *testing.T) { |
3114 | - now := func(offset int) time.Time { |
3115 | - return time.Now().Add(time.Duration(offset) * time.Second) |
3116 | - } |
3117 | - |
3118 | - for i, tc := range []struct { |
3119 | - start, end time.Time |
3120 | - err bool |
3121 | - code int |
3122 | - }{ |
3123 | - {time.Time{}, time.Time{}, false, 200}, |
3124 | - {now(0), time.Time{}, false, 200}, |
3125 | - {time.Time{}, now(-1), false, 200}, |
3126 | - {time.Time{}, now(0), false, 200}, |
3127 | - {time.Time{}, now(1), false, 200}, |
3128 | - {now(-2), now(-1), false, 200}, |
3129 | - {now(1), now(2), false, 200}, |
3130 | - {now(1), now(0), false, 400}, |
3131 | - {now(0), time.Time{}, true, 500}, |
3132 | - } { |
3133 | - alerts := []model.Alert{{ |
3134 | - StartsAt: tc.start, |
3135 | - EndsAt: tc.end, |
3136 | - Labels: model.LabelSet{"label1": "test1"}, |
3137 | - Annotations: model.LabelSet{"annotation1": "some text"}, |
3138 | - }} |
3139 | - b, err := json.Marshal(&alerts) |
3140 | - if err != nil { |
3141 | - t.Errorf("Unexpected error %v", err) |
3142 | - } |
3143 | - |
3144 | - alertsProvider := newFakeAlerts([]*types.Alert{}, tc.err) |
3145 | - api := New(alertsProvider, nil, newGetAlertStatus(alertsProvider), nil, nil, nil) |
3146 | - defaultGlobalConfig := config.DefaultGlobalConfig() |
3147 | - route := config.Route{} |
3148 | - api.Update(&config.Config{ |
3149 | - Global: &defaultGlobalConfig, |
3150 | - Route: &route, |
3151 | - }) |
3152 | - |
3153 | - r, err := http.NewRequest("POST", "/api/v1/alerts", bytes.NewReader(b)) |
3154 | - w := httptest.NewRecorder() |
3155 | - if err != nil { |
3156 | - t.Errorf("Unexpected error %v", err) |
3157 | - } |
3158 | - |
3159 | - api.addAlerts(w, r) |
3160 | - res := w.Result() |
3161 | - body, _ := ioutil.ReadAll(res.Body) |
3162 | - |
3163 | - require.Equal(t, tc.code, w.Code, fmt.Sprintf("test case: %d, StartsAt %v, EndsAt %v, Response: %s", i, tc.start, tc.end, string(body))) |
3164 | - } |
3165 | -} |
3166 | - |
3167 | -func TestListAlerts(t *testing.T) { |
3168 | - now := time.Now() |
3169 | - alerts := []*types.Alert{ |
3170 | - &types.Alert{ |
3171 | - Alert: model.Alert{ |
3172 | - Labels: model.LabelSet{"state": "active", "alertname": "alert1"}, |
3173 | - StartsAt: now.Add(-time.Minute), |
3174 | - }, |
3175 | - }, |
3176 | - &types.Alert{ |
3177 | - Alert: model.Alert{ |
3178 | - Labels: model.LabelSet{"state": "unprocessed", "alertname": "alert2"}, |
3179 | - StartsAt: now.Add(-time.Minute), |
3180 | - }, |
3181 | - }, |
3182 | - &types.Alert{ |
3183 | - Alert: model.Alert{ |
3184 | - Labels: model.LabelSet{"state": "suppressed", "silenced_by": "abc", "alertname": "alert3"}, |
3185 | - StartsAt: now.Add(-time.Minute), |
3186 | - }, |
3187 | - }, |
3188 | - &types.Alert{ |
3189 | - Alert: model.Alert{ |
3190 | - Labels: model.LabelSet{"state": "suppressed", "inhibited_by": "abc", "alertname": "alert4"}, |
3191 | - StartsAt: now.Add(-time.Minute), |
3192 | - }, |
3193 | - }, |
3194 | - &types.Alert{ |
3195 | - Alert: model.Alert{ |
3196 | - Labels: model.LabelSet{"alertname": "alert5"}, |
3197 | - StartsAt: now.Add(-2 * time.Minute), |
3198 | - EndsAt: now.Add(-time.Minute), |
3199 | - }, |
3200 | - }, |
3201 | - } |
3202 | - |
3203 | - for i, tc := range []struct { |
3204 | - err bool |
3205 | - params map[string]string |
3206 | - |
3207 | - code int |
3208 | - anames []string |
3209 | - }{ |
3210 | - { |
3211 | - false, |
3212 | - map[string]string{}, |
3213 | - 200, |
3214 | - []string{"alert1", "alert2", "alert3", "alert4"}, |
3215 | - }, |
3216 | - { |
3217 | - false, |
3218 | - map[string]string{"active": "true", "unprocessed": "true", "silenced": "true", "inhibited": "true"}, |
3219 | - 200, |
3220 | - []string{"alert1", "alert2", "alert3", "alert4"}, |
3221 | - }, |
3222 | - { |
3223 | - false, |
3224 | - map[string]string{"active": "false", "unprocessed": "true", "silenced": "true", "inhibited": "true"}, |
3225 | - 200, |
3226 | - []string{"alert2", "alert3", "alert4"}, |
3227 | - }, |
3228 | - { |
3229 | - false, |
3230 | - map[string]string{"active": "true", "unprocessed": "false", "silenced": "true", "inhibited": "true"}, |
3231 | - 200, |
3232 | - []string{"alert1", "alert3", "alert4"}, |
3233 | - }, |
3234 | - { |
3235 | - false, |
3236 | - map[string]string{"active": "true", "unprocessed": "true", "silenced": "false", "inhibited": "true"}, |
3237 | - 200, |
3238 | - []string{"alert1", "alert2", "alert4"}, |
3239 | - }, |
3240 | - { |
3241 | - false, |
3242 | - map[string]string{"active": "true", "unprocessed": "true", "silenced": "true", "inhibited": "false"}, |
3243 | - 200, |
3244 | - []string{"alert1", "alert2", "alert3"}, |
3245 | - }, |
3246 | - { |
3247 | - false, |
3248 | - map[string]string{"filter": "{alertname=\"alert3\""}, |
3249 | - 200, |
3250 | - []string{"alert3"}, |
3251 | - }, |
3252 | - { |
3253 | - false, |
3254 | - map[string]string{"filter": "{alertname"}, |
3255 | - 400, |
3256 | - []string{}, |
3257 | - }, |
3258 | - { |
3259 | - false, |
3260 | - map[string]string{"receiver": "other"}, |
3261 | - 200, |
3262 | - []string{}, |
3263 | - }, |
3264 | - { |
3265 | - false, |
3266 | - map[string]string{"active": "invalid"}, |
3267 | - 400, |
3268 | - []string{}, |
3269 | - }, |
3270 | - { |
3271 | - true, |
3272 | - map[string]string{}, |
3273 | - 500, |
3274 | - []string{}, |
3275 | - }, |
3276 | - } { |
3277 | - alertsProvider := newFakeAlerts(alerts, tc.err) |
3278 | - api := New(alertsProvider, nil, newGetAlertStatus(alertsProvider), nil, nil, nil) |
3279 | - api.route = dispatch.NewRoute(&config.Route{Receiver: "def-receiver"}, nil) |
3280 | - |
3281 | - r, err := http.NewRequest("GET", "/api/v1/alerts", nil) |
3282 | - if err != nil { |
3283 | - t.Fatalf("Unexpected error %v", err) |
3284 | - } |
3285 | - q := r.URL.Query() |
3286 | - for k, v := range tc.params { |
3287 | - q.Add(k, v) |
3288 | - } |
3289 | - r.URL.RawQuery = q.Encode() |
3290 | - w := httptest.NewRecorder() |
3291 | - |
3292 | - api.listAlerts(w, r) |
3293 | - body, _ := ioutil.ReadAll(w.Result().Body) |
3294 | - |
3295 | - var res response |
3296 | - err = json.Unmarshal(body, &res) |
3297 | - if err != nil { |
3298 | - t.Fatalf("Unexpected error %v", err) |
3299 | - } |
3300 | - |
3301 | - require.Equal(t, tc.code, w.Code, fmt.Sprintf("test case: %d, response: %s", i, string(body))) |
3302 | - if w.Code != 200 { |
3303 | - continue |
3304 | - } |
3305 | - |
3306 | - // Data needs to be serialized/deserialized to be converted to the real type. |
3307 | - b, err := json.Marshal(res.Data) |
3308 | - if err != nil { |
3309 | - t.Fatalf("Unexpected error %v", err) |
3310 | - } |
3311 | - retAlerts := []*Alert{} |
3312 | - err = json.Unmarshal(b, &retAlerts) |
3313 | - if err != nil { |
3314 | - t.Fatalf("Unexpected error %v", err) |
3315 | - } |
3316 | - |
3317 | - anames := []string{} |
3318 | - for _, a := range retAlerts { |
3319 | - name, ok := a.Labels["alertname"] |
3320 | - if ok { |
3321 | - anames = append(anames, string(name)) |
3322 | - } |
3323 | - } |
3324 | - require.Equal(t, tc.anames, anames, fmt.Sprintf("test case: %d, alert names are not equal", i)) |
3325 | - } |
3326 | -} |
3327 | - |
3328 | -func TestAlertFiltering(t *testing.T) { |
3329 | - type test struct { |
3330 | - alert *model.Alert |
3331 | - msg string |
3332 | - expected bool |
3333 | - } |
3334 | - |
3335 | - // Equal |
3336 | - equal, err := labels.NewMatcher(labels.MatchEqual, "label1", "test1") |
3337 | - if err != nil { |
3338 | - t.Errorf("Unexpected error %v", err) |
3339 | - } |
3340 | - |
3341 | - tests := []test{ |
3342 | - {&model.Alert{Labels: model.LabelSet{"label1": "test1"}}, "label1=test1", true}, |
3343 | - {&model.Alert{Labels: model.LabelSet{"label1": "test2"}}, "label1=test2", false}, |
3344 | - {&model.Alert{Labels: model.LabelSet{"label2": "test2"}}, "label2=test2", false}, |
3345 | - } |
3346 | - |
3347 | - for _, test := range tests { |
3348 | - actual := alertMatchesFilterLabels(test.alert, []*labels.Matcher{equal}) |
3349 | - msg := fmt.Sprintf("Expected %t for %s", test.expected, test.msg) |
3350 | - require.Equal(t, test.expected, actual, msg) |
3351 | - } |
3352 | - |
3353 | - // Not Equal |
3354 | - notEqual, err := labels.NewMatcher(labels.MatchNotEqual, "label1", "test1") |
3355 | - if err != nil { |
3356 | - t.Errorf("Unexpected error %v", err) |
3357 | - } |
3358 | - |
3359 | - tests = []test{ |
3360 | - {&model.Alert{Labels: model.LabelSet{"label1": "test1"}}, "label1!=test1", false}, |
3361 | - {&model.Alert{Labels: model.LabelSet{"label1": "test2"}}, "label1!=test2", true}, |
3362 | - {&model.Alert{Labels: model.LabelSet{"label2": "test2"}}, "label2!=test2", true}, |
3363 | - } |
3364 | - |
3365 | - for _, test := range tests { |
3366 | - actual := alertMatchesFilterLabels(test.alert, []*labels.Matcher{notEqual}) |
3367 | - msg := fmt.Sprintf("Expected %t for %s", test.expected, test.msg) |
3368 | - require.Equal(t, test.expected, actual, msg) |
3369 | - } |
3370 | - |
3371 | - // Regexp Equal |
3372 | - regexpEqual, err := labels.NewMatcher(labels.MatchRegexp, "label1", "tes.*") |
3373 | - if err != nil { |
3374 | - t.Errorf("Unexpected error %v", err) |
3375 | - } |
3376 | - |
3377 | - tests = []test{ |
3378 | - {&model.Alert{Labels: model.LabelSet{"label1": "test1"}}, "label1=~test1", true}, |
3379 | - {&model.Alert{Labels: model.LabelSet{"label1": "test2"}}, "label1=~test2", true}, |
3380 | - {&model.Alert{Labels: model.LabelSet{"label2": "test2"}}, "label2=~test2", false}, |
3381 | - } |
3382 | - |
3383 | - for _, test := range tests { |
3384 | - actual := alertMatchesFilterLabels(test.alert, []*labels.Matcher{regexpEqual}) |
3385 | - msg := fmt.Sprintf("Expected %t for %s", test.expected, test.msg) |
3386 | - require.Equal(t, test.expected, actual, msg) |
3387 | - } |
3388 | - |
3389 | - // Regexp Not Equal |
3390 | - regexpNotEqual, err := labels.NewMatcher(labels.MatchNotRegexp, "label1", "tes.*") |
3391 | - if err != nil { |
3392 | - t.Errorf("Unexpected error %v", err) |
3393 | - } |
3394 | - |
3395 | - tests = []test{ |
3396 | - {&model.Alert{Labels: model.LabelSet{"label1": "test1"}}, "label1!~test1", false}, |
3397 | - {&model.Alert{Labels: model.LabelSet{"label1": "test2"}}, "label1!~test2", false}, |
3398 | - {&model.Alert{Labels: model.LabelSet{"label2": "test2"}}, "label2!~test2", true}, |
3399 | - } |
3400 | - |
3401 | - for _, test := range tests { |
3402 | - actual := alertMatchesFilterLabels(test.alert, []*labels.Matcher{regexpNotEqual}) |
3403 | - msg := fmt.Sprintf("Expected %t for %s", test.expected, test.msg) |
3404 | - require.Equal(t, test.expected, actual, msg) |
3405 | - } |
3406 | -} |
3407 | - |
3408 | -func TestSilenceFiltering(t *testing.T) { |
3409 | - type test struct { |
3410 | - silence *types.Silence |
3411 | - msg string |
3412 | - expected bool |
3413 | - } |
3414 | - |
3415 | - // Equal |
3416 | - equal, err := labels.NewMatcher(labels.MatchEqual, "label1", "test1") |
3417 | - if err != nil { |
3418 | - t.Errorf("Unexpected error %v", err) |
3419 | - } |
3420 | - |
3421 | - tests := []test{ |
3422 | - { |
3423 | - &types.Silence{Matchers: newMatcher(model.LabelSet{"label1": "test1"})}, |
3424 | - "label1=test1", |
3425 | - true, |
3426 | - }, |
3427 | - { |
3428 | - &types.Silence{Matchers: newMatcher(model.LabelSet{"label1": "test2"})}, |
3429 | - "label1=test2", |
3430 | - false, |
3431 | - }, |
3432 | - { |
3433 | - &types.Silence{Matchers: newMatcher(model.LabelSet{"label2": "test2"})}, |
3434 | - "label2=test2", |
3435 | - false, |
3436 | - }, |
3437 | - } |
3438 | - |
3439 | - for _, test := range tests { |
3440 | - actual := silenceMatchesFilterLabels(test.silence, []*labels.Matcher{equal}) |
3441 | - msg := fmt.Sprintf("Expected %t for %s", test.expected, test.msg) |
3442 | - require.Equal(t, test.expected, actual, msg) |
3443 | - } |
3444 | - |
3445 | - // Not Equal |
3446 | - notEqual, err := labels.NewMatcher(labels.MatchNotEqual, "label1", "test1") |
3447 | - if err != nil { |
3448 | - t.Errorf("Unexpected error %v", err) |
3449 | - } |
3450 | - |
3451 | - tests = []test{ |
3452 | - { |
3453 | - &types.Silence{Matchers: newMatcher(model.LabelSet{"label1": "test1"})}, |
3454 | - "label1!=test1", |
3455 | - false, |
3456 | - }, |
3457 | - { |
3458 | - &types.Silence{Matchers: newMatcher(model.LabelSet{"label1": "test2"})}, |
3459 | - "label1!=test2", |
3460 | - true, |
3461 | - }, |
3462 | - { |
3463 | - &types.Silence{Matchers: newMatcher(model.LabelSet{"label2": "test2"})}, |
3464 | - "label2!=test2", |
3465 | - true, |
3466 | - }, |
3467 | - } |
3468 | - |
3469 | - for _, test := range tests { |
3470 | - actual := silenceMatchesFilterLabels(test.silence, []*labels.Matcher{notEqual}) |
3471 | - msg := fmt.Sprintf("Expected %t for %s", test.expected, test.msg) |
3472 | - require.Equal(t, test.expected, actual, msg) |
3473 | - } |
3474 | - |
3475 | - // Regexp Equal |
3476 | - regexpEqual, err := labels.NewMatcher(labels.MatchRegexp, "label1", "tes.*") |
3477 | - if err != nil { |
3478 | - t.Errorf("Unexpected error %v", err) |
3479 | - } |
3480 | - |
3481 | - tests = []test{ |
3482 | - { |
3483 | - &types.Silence{Matchers: newMatcher(model.LabelSet{"label1": "test1"})}, |
3484 | - "label1=~test1", |
3485 | - true, |
3486 | - }, |
3487 | - { |
3488 | - &types.Silence{Matchers: newMatcher(model.LabelSet{"label1": "test2"})}, |
3489 | - "label1=~test2", |
3490 | - true, |
3491 | - }, |
3492 | - { |
3493 | - &types.Silence{Matchers: newMatcher(model.LabelSet{"label2": "test2"})}, |
3494 | - "label2=~test2", |
3495 | - false, |
3496 | - }, |
3497 | - } |
3498 | - |
3499 | - for _, test := range tests { |
3500 | - actual := silenceMatchesFilterLabels(test.silence, []*labels.Matcher{regexpEqual}) |
3501 | - msg := fmt.Sprintf("Expected %t for %s", test.expected, test.msg) |
3502 | - require.Equal(t, test.expected, actual, msg) |
3503 | - } |
3504 | - |
3505 | - // Regexp Not Equal |
3506 | - regexpNotEqual, err := labels.NewMatcher(labels.MatchNotRegexp, "label1", "tes.*") |
3507 | - if err != nil { |
3508 | - t.Errorf("Unexpected error %v", err) |
3509 | - } |
3510 | - |
3511 | - tests = []test{ |
3512 | - { |
3513 | - &types.Silence{Matchers: newMatcher(model.LabelSet{"label1": "test1"})}, |
3514 | - "label1!~test1", |
3515 | - false, |
3516 | - }, |
3517 | - { |
3518 | - &types.Silence{Matchers: newMatcher(model.LabelSet{"label1": "test2"})}, |
3519 | - "label1!~test2", |
3520 | - false, |
3521 | - }, |
3522 | - { |
3523 | - &types.Silence{Matchers: newMatcher(model.LabelSet{"label2": "test2"})}, |
3524 | - "label2!~test2", |
3525 | - true, |
3526 | - }, |
3527 | - } |
3528 | - |
3529 | - for _, test := range tests { |
3530 | - actual := silenceMatchesFilterLabels(test.silence, []*labels.Matcher{regexpNotEqual}) |
3531 | - msg := fmt.Sprintf("Expected %t for %s", test.expected, test.msg) |
3532 | - require.Equal(t, test.expected, actual, msg) |
3533 | - } |
3534 | -} |
3535 | - |
3536 | -func TestReceiversMatchFilter(t *testing.T) { |
3537 | - receivers := []string{"pagerduty", "slack", "pushover"} |
3538 | - |
3539 | - filter, err := regexp.Compile(fmt.Sprintf("^(?:%s)$", "push.*")) |
3540 | - if err != nil { |
3541 | - t.Errorf("Unexpected error %v", err) |
3542 | - } |
3543 | - require.True(t, receiversMatchFilter(receivers, filter)) |
3544 | - |
3545 | - filter, err = regexp.Compile(fmt.Sprintf("^(?:%s)$", "push")) |
3546 | - if err != nil { |
3547 | - t.Errorf("Unexpected error %v", err) |
3548 | - } |
3549 | - require.False(t, receiversMatchFilter(receivers, filter)) |
3550 | -} |
3551 | - |
3552 | -func TestMatchFilterLabels(t *testing.T) { |
3553 | - testCases := []struct { |
3554 | - matcher labels.MatchType |
3555 | - expected bool |
3556 | - }{ |
3557 | - {labels.MatchEqual, true}, |
3558 | - {labels.MatchRegexp, true}, |
3559 | - {labels.MatchNotEqual, false}, |
3560 | - {labels.MatchNotRegexp, false}, |
3561 | - } |
3562 | - |
3563 | - for _, tc := range testCases { |
3564 | - l, err := labels.NewMatcher(tc.matcher, "foo", "") |
3565 | - require.NoError(t, err) |
3566 | - sms := map[string]string{ |
3567 | - "baz": "bar", |
3568 | - } |
3569 | - ls := []*labels.Matcher{l} |
3570 | - |
3571 | - require.Equal(t, tc.expected, matchFilterLabels(ls, sms)) |
3572 | - |
3573 | - l, err = labels.NewMatcher(tc.matcher, "foo", "") |
3574 | - require.NoError(t, err) |
3575 | - sms = map[string]string{ |
3576 | - "baz": "bar", |
3577 | - "foo": "quux", |
3578 | - } |
3579 | - ls = []*labels.Matcher{l} |
3580 | - require.NotEqual(t, tc.expected, matchFilterLabels(ls, sms)) |
3581 | - } |
3582 | -} |
3583 | - |
3584 | -func newMatcher(labelSet model.LabelSet) types.Matchers { |
3585 | - matchers := make([]*types.Matcher, 0, len(labelSet)) |
3586 | - for key, val := range labelSet { |
3587 | - matchers = append(matchers, types.NewMatcher(key, string(val))) |
3588 | - } |
3589 | - return matchers |
3590 | -} |
3591 | diff --git a/api/v2/api.go b/api/v2/api.go |
3592 | deleted file mode 100644 |
3593 | index 6cde197..0000000 |
3594 | --- a/api/v2/api.go |
3595 | +++ /dev/null |
3596 | @@ -1,798 +0,0 @@ |
3597 | -// Copyright 2018 Prometheus Team |
3598 | -// Licensed under the Apache License, Version 2.0 (the "License"); |
3599 | -// you may not use this file except in compliance with the License. |
3600 | -// You may obtain a copy of the License at |
3601 | -// |
3602 | -// http://www.apache.org/licenses/LICENSE-2.0 |
3603 | -// |
3604 | -// Unless required by applicable law or agreed to in writing, software |
3605 | -// distributed under the License is distributed on an "AS IS" BASIS, |
3606 | -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
3607 | -// See the License for the specific language governing permissions and |
3608 | -// limitations under the License. |
3609 | - |
3610 | -package v2 |
3611 | - |
3612 | -import ( |
3613 | - "fmt" |
3614 | - "net/http" |
3615 | - "regexp" |
3616 | - "sort" |
3617 | - "sync" |
3618 | - "time" |
3619 | - |
3620 | - "github.com/go-kit/kit/log" |
3621 | - "github.com/go-kit/kit/log/level" |
3622 | - "github.com/go-openapi/loads" |
3623 | - "github.com/go-openapi/runtime/middleware" |
3624 | - "github.com/go-openapi/strfmt" |
3625 | - "github.com/prometheus/client_golang/prometheus" |
3626 | - prometheus_model "github.com/prometheus/common/model" |
3627 | - "github.com/prometheus/common/version" |
3628 | - "github.com/rs/cors" |
3629 | - |
3630 | - "github.com/prometheus/alertmanager/api/metrics" |
3631 | - open_api_models "github.com/prometheus/alertmanager/api/v2/models" |
3632 | - "github.com/prometheus/alertmanager/api/v2/restapi" |
3633 | - "github.com/prometheus/alertmanager/api/v2/restapi/operations" |
3634 | - alert_ops "github.com/prometheus/alertmanager/api/v2/restapi/operations/alert" |
3635 | - alertgroup_ops "github.com/prometheus/alertmanager/api/v2/restapi/operations/alertgroup" |
3636 | - general_ops "github.com/prometheus/alertmanager/api/v2/restapi/operations/general" |
3637 | - receiver_ops "github.com/prometheus/alertmanager/api/v2/restapi/operations/receiver" |
3638 | - silence_ops "github.com/prometheus/alertmanager/api/v2/restapi/operations/silence" |
3639 | - "github.com/prometheus/alertmanager/cluster" |
3640 | - "github.com/prometheus/alertmanager/config" |
3641 | - "github.com/prometheus/alertmanager/dispatch" |
3642 | - "github.com/prometheus/alertmanager/pkg/labels" |
3643 | - "github.com/prometheus/alertmanager/provider" |
3644 | - "github.com/prometheus/alertmanager/silence" |
3645 | - "github.com/prometheus/alertmanager/silence/silencepb" |
3646 | - "github.com/prometheus/alertmanager/types" |
3647 | -) |
3648 | - |
3649 | -// API represents an Alertmanager API v2 |
3650 | -type API struct { |
3651 | - peer *cluster.Peer |
3652 | - silences *silence.Silences |
3653 | - alerts provider.Alerts |
3654 | - alertGroups groupsFn |
3655 | - getAlertStatus getAlertStatusFn |
3656 | - uptime time.Time |
3657 | - |
3658 | - // mtx protects alertmanagerConfig, setAlertStatus and route. |
3659 | - mtx sync.RWMutex |
3660 | - // resolveTimeout represents the default resolve timeout that an alert is |
3661 | - // assigned if no end time is specified. |
3662 | - alertmanagerConfig *config.Config |
3663 | - route *dispatch.Route |
3664 | - setAlertStatus setAlertStatusFn |
3665 | - |
3666 | - logger log.Logger |
3667 | - m *metrics.Alerts |
3668 | - |
3669 | - Handler http.Handler |
3670 | -} |
3671 | - |
3672 | -type groupsFn func(func(*dispatch.Route) bool, func(*types.Alert, time.Time) bool) (dispatch.AlertGroups, map[prometheus_model.Fingerprint][]string) |
3673 | -type getAlertStatusFn func(prometheus_model.Fingerprint) types.AlertStatus |
3674 | -type setAlertStatusFn func(prometheus_model.LabelSet) |
3675 | - |
3676 | -// NewAPI returns a new Alertmanager API v2 |
3677 | -func NewAPI( |
3678 | - alerts provider.Alerts, |
3679 | - gf groupsFn, |
3680 | - sf getAlertStatusFn, |
3681 | - silences *silence.Silences, |
3682 | - peer *cluster.Peer, |
3683 | - l log.Logger, |
3684 | - r prometheus.Registerer, |
3685 | -) (*API, error) { |
3686 | - api := API{ |
3687 | - alerts: alerts, |
3688 | - getAlertStatus: sf, |
3689 | - alertGroups: gf, |
3690 | - peer: peer, |
3691 | - silences: silences, |
3692 | - logger: l, |
3693 | - m: metrics.NewAlerts("v2", r), |
3694 | - uptime: time.Now(), |
3695 | - } |
3696 | - |
3697 | - // Load embedded swagger file. |
3698 | - swaggerSpec, err := loads.Analyzed(restapi.SwaggerJSON, "") |
3699 | - if err != nil { |
3700 | - return nil, fmt.Errorf("failed to load embedded swagger file: %v", err.Error()) |
3701 | - } |
3702 | - |
3703 | - // Create new service API. |
3704 | - openAPI := operations.NewAlertmanagerAPI(swaggerSpec) |
3705 | - |
3706 | - // Skip the redoc middleware, only serving the OpenAPI specification and |
3707 | - // the API itself via RoutesHandler. See: |
3708 | - // https://github.com/go-swagger/go-swagger/issues/1779 |
3709 | - openAPI.Middleware = func(b middleware.Builder) http.Handler { |
3710 | - return middleware.Spec("", swaggerSpec.Raw(), openAPI.Context().RoutesHandler(b)) |
3711 | - } |
3712 | - |
3713 | - openAPI.AlertGetAlertsHandler = alert_ops.GetAlertsHandlerFunc(api.getAlertsHandler) |
3714 | - openAPI.AlertPostAlertsHandler = alert_ops.PostAlertsHandlerFunc(api.postAlertsHandler) |
3715 | - openAPI.AlertgroupGetAlertGroupsHandler = alertgroup_ops.GetAlertGroupsHandlerFunc(api.getAlertGroupsHandler) |
3716 | - openAPI.GeneralGetStatusHandler = general_ops.GetStatusHandlerFunc(api.getStatusHandler) |
3717 | - openAPI.ReceiverGetReceiversHandler = receiver_ops.GetReceiversHandlerFunc(api.getReceiversHandler) |
3718 | - openAPI.SilenceDeleteSilenceHandler = silence_ops.DeleteSilenceHandlerFunc(api.deleteSilenceHandler) |
3719 | - openAPI.SilenceGetSilenceHandler = silence_ops.GetSilenceHandlerFunc(api.getSilenceHandler) |
3720 | - openAPI.SilenceGetSilencesHandler = silence_ops.GetSilencesHandlerFunc(api.getSilencesHandler) |
3721 | - openAPI.SilencePostSilencesHandler = silence_ops.PostSilencesHandlerFunc(api.postSilencesHandler) |
3722 | - |
3723 | - handleCORS := cors.Default().Handler |
3724 | - api.Handler = handleCORS(openAPI.Serve(nil)) |
3725 | - |
3726 | - return &api, nil |
3727 | -} |
3728 | - |
3729 | -func (api *API) requestLogger(req *http.Request) log.Logger { |
3730 | - return log.With(api.logger, "path", req.URL.Path, "method", req.Method) |
3731 | -} |
3732 | - |
3733 | -// Update sets the API struct members that may change between reloads of alertmanager. |
3734 | -func (api *API) Update(cfg *config.Config, setAlertStatus setAlertStatusFn) { |
3735 | - api.mtx.Lock() |
3736 | - defer api.mtx.Unlock() |
3737 | - |
3738 | - api.alertmanagerConfig = cfg |
3739 | - api.route = dispatch.NewRoute(cfg.Route, nil) |
3740 | - api.setAlertStatus = setAlertStatus |
3741 | -} |
3742 | - |
3743 | -func (api *API) getStatusHandler(params general_ops.GetStatusParams) middleware.Responder { |
3744 | - api.mtx.RLock() |
3745 | - defer api.mtx.RUnlock() |
3746 | - |
3747 | - original := api.alertmanagerConfig.String() |
3748 | - uptime := strfmt.DateTime(api.uptime) |
3749 | - |
3750 | - status := open_api_models.ClusterStatusStatusDisabled |
3751 | - |
3752 | - resp := open_api_models.AlertmanagerStatus{ |
3753 | - Uptime: &uptime, |
3754 | - VersionInfo: &open_api_models.VersionInfo{ |
3755 | - Version: &version.Version, |
3756 | - Revision: &version.Revision, |
3757 | - Branch: &version.Branch, |
3758 | - BuildUser: &version.BuildUser, |
3759 | - BuildDate: &version.BuildDate, |
3760 | - GoVersion: &version.GoVersion, |
3761 | - }, |
3762 | - Config: &open_api_models.AlertmanagerConfig{ |
3763 | - Original: &original, |
3764 | - }, |
3765 | - Cluster: &open_api_models.ClusterStatus{ |
3766 | - Status: &status, |
3767 | - Peers: []*open_api_models.PeerStatus{}, |
3768 | - }, |
3769 | - } |
3770 | - |
3771 | - // If alertmanager cluster feature is disabled, then api.peers == nil. |
3772 | - if api.peer != nil { |
3773 | - status := api.peer.Status() |
3774 | - |
3775 | - peers := []*open_api_models.PeerStatus{} |
3776 | - for _, n := range api.peer.Peers() { |
3777 | - address := n.Address() |
3778 | - peers = append(peers, &open_api_models.PeerStatus{ |
3779 | - Name: &n.Name, |
3780 | - Address: &address, |
3781 | - }) |
3782 | - } |
3783 | - |
3784 | - sort.Slice(peers, func(i, j int) bool { |
3785 | - return *peers[i].Name < *peers[j].Name |
3786 | - }) |
3787 | - |
3788 | - resp.Cluster = &open_api_models.ClusterStatus{ |
3789 | - Name: api.peer.Name(), |
3790 | - Status: &status, |
3791 | - Peers: peers, |
3792 | - } |
3793 | - } |
3794 | - |
3795 | - return general_ops.NewGetStatusOK().WithPayload(&resp) |
3796 | -} |
3797 | - |
3798 | -func (api *API) getReceiversHandler(params receiver_ops.GetReceiversParams) middleware.Responder { |
3799 | - api.mtx.RLock() |
3800 | - defer api.mtx.RUnlock() |
3801 | - |
3802 | - receivers := make([]*open_api_models.Receiver, 0, len(api.alertmanagerConfig.Receivers)) |
3803 | - for _, r := range api.alertmanagerConfig.Receivers { |
3804 | - receivers = append(receivers, &open_api_models.Receiver{Name: &r.Name}) |
3805 | - } |
3806 | - |
3807 | - return receiver_ops.NewGetReceiversOK().WithPayload(receivers) |
3808 | -} |
3809 | - |
3810 | -func (api *API) getAlertsHandler(params alert_ops.GetAlertsParams) middleware.Responder { |
3811 | - var ( |
3812 | - receiverFilter *regexp.Regexp |
3813 | - // Initialize result slice to prevent api returning `null` when there |
3814 | - // are no alerts present |
3815 | - res = open_api_models.GettableAlerts{} |
3816 | - ctx = params.HTTPRequest.Context() |
3817 | - |
3818 | - logger = api.requestLogger(params.HTTPRequest) |
3819 | - ) |
3820 | - |
3821 | - matchers, err := parseFilter(params.Filter) |
3822 | - if err != nil { |
3823 | - level.Error(logger).Log("msg", "Failed to parse matchers", "err", err) |
3824 | - return alertgroup_ops.NewGetAlertGroupsBadRequest().WithPayload(err.Error()) |
3825 | - } |
3826 | - |
3827 | - if params.Receiver != nil { |
3828 | - receiverFilter, err = regexp.Compile("^(?:" + *params.Receiver + ")$") |
3829 | - if err != nil { |
3830 | - level.Error(logger).Log("msg", "Failed to compile receiver regex", "err", err) |
3831 | - return alert_ops. |
3832 | - NewGetAlertsBadRequest(). |
3833 | - WithPayload( |
3834 | - fmt.Sprintf("failed to parse receiver param: %v", err.Error()), |
3835 | - ) |
3836 | - } |
3837 | - } |
3838 | - |
3839 | - alerts := api.alerts.GetPending() |
3840 | - defer alerts.Close() |
3841 | - |
3842 | - alertFilter := api.alertFilter(matchers, *params.Silenced, *params.Inhibited, *params.Active) |
3843 | - now := time.Now() |
3844 | - |
3845 | - api.mtx.RLock() |
3846 | - for a := range alerts.Next() { |
3847 | - if err = alerts.Err(); err != nil { |
3848 | - break |
3849 | - } |
3850 | - if err = ctx.Err(); err != nil { |
3851 | - break |
3852 | - } |
3853 | - |
3854 | - routes := api.route.Match(a.Labels) |
3855 | - receivers := make([]string, 0, len(routes)) |
3856 | - for _, r := range routes { |
3857 | - receivers = append(receivers, r.RouteOpts.Receiver) |
3858 | - } |
3859 | - |
3860 | - if receiverFilter != nil && !receiversMatchFilter(receivers, receiverFilter) { |
3861 | - continue |
3862 | - } |
3863 | - |
3864 | - if !alertFilter(a, now) { |
3865 | - continue |
3866 | - } |
3867 | - |
3868 | - alert := alertToOpenAPIAlert(a, api.getAlertStatus(a.Fingerprint()), receivers) |
3869 | - |
3870 | - res = append(res, alert) |
3871 | - } |
3872 | - api.mtx.RUnlock() |
3873 | - |
3874 | - if err != nil { |
3875 | - level.Error(logger).Log("msg", "Failed to get alerts", "err", err) |
3876 | - return alert_ops.NewGetAlertsInternalServerError().WithPayload(err.Error()) |
3877 | - } |
3878 | - sort.Slice(res, func(i, j int) bool { |
3879 | - return *res[i].Fingerprint < *res[j].Fingerprint |
3880 | - }) |
3881 | - |
3882 | - return alert_ops.NewGetAlertsOK().WithPayload(res) |
3883 | -} |
3884 | - |
3885 | -func (api *API) postAlertsHandler(params alert_ops.PostAlertsParams) middleware.Responder { |
3886 | - logger := api.requestLogger(params.HTTPRequest) |
3887 | - |
3888 | - alerts := openAPIAlertsToAlerts(params.Alerts) |
3889 | - now := time.Now() |
3890 | - |
3891 | - api.mtx.RLock() |
3892 | - resolveTimeout := time.Duration(api.alertmanagerConfig.Global.ResolveTimeout) |
3893 | - api.mtx.RUnlock() |
3894 | - |
3895 | - for _, alert := range alerts { |
3896 | - alert.UpdatedAt = now |
3897 | - |
3898 | - // Ensure StartsAt is set. |
3899 | - if alert.StartsAt.IsZero() { |
3900 | - if alert.EndsAt.IsZero() { |
3901 | - alert.StartsAt = now |
3902 | - } else { |
3903 | - alert.StartsAt = alert.EndsAt |
3904 | - } |
3905 | - } |
3906 | - // If no end time is defined, set a timeout after which an alert |
3907 | - // is marked resolved if it is not updated. |
3908 | - if alert.EndsAt.IsZero() { |
3909 | - alert.Timeout = true |
3910 | - alert.EndsAt = now.Add(resolveTimeout) |
3911 | - } |
3912 | - if alert.EndsAt.After(time.Now()) { |
3913 | - api.m.Firing().Inc() |
3914 | - } else { |
3915 | - api.m.Resolved().Inc() |
3916 | - } |
3917 | - } |
3918 | - |
3919 | - // Make a best effort to insert all alerts that are valid. |
3920 | - var ( |
3921 | - validAlerts = make([]*types.Alert, 0, len(alerts)) |
3922 | - validationErrs = &types.MultiError{} |
3923 | - ) |
3924 | - for _, a := range alerts { |
3925 | - removeEmptyLabels(a.Labels) |
3926 | - |
3927 | - if err := a.Validate(); err != nil { |
3928 | - validationErrs.Add(err) |
3929 | - api.m.Invalid().Inc() |
3930 | - continue |
3931 | - } |
3932 | - validAlerts = append(validAlerts, a) |
3933 | - } |
3934 | - if err := api.alerts.Put(validAlerts...); err != nil { |
3935 | - level.Error(logger).Log("msg", "Failed to create alerts", "err", err) |
3936 | - return alert_ops.NewPostAlertsInternalServerError().WithPayload(err.Error()) |
3937 | - } |
3938 | - |
3939 | - if validationErrs.Len() > 0 { |
3940 | - level.Error(logger).Log("msg", "Failed to validate alerts", "err", validationErrs.Error()) |
3941 | - return alert_ops.NewPostAlertsBadRequest().WithPayload(validationErrs.Error()) |
3942 | - } |
3943 | - |
3944 | - return alert_ops.NewPostAlertsOK() |
3945 | -} |
3946 | - |
3947 | -func (api *API) getAlertGroupsHandler(params alertgroup_ops.GetAlertGroupsParams) middleware.Responder { |
3948 | - logger := api.requestLogger(params.HTTPRequest) |
3949 | - |
3950 | - matchers, err := parseFilter(params.Filter) |
3951 | - if err != nil { |
3952 | - level.Error(logger).Log("msg", "Failed to parse matchers", "err", err) |
3953 | - return alertgroup_ops.NewGetAlertGroupsBadRequest().WithPayload(err.Error()) |
3954 | - } |
3955 | - |
3956 | - var receiverFilter *regexp.Regexp |
3957 | - if params.Receiver != nil { |
3958 | - receiverFilter, err = regexp.Compile("^(?:" + *params.Receiver + ")$") |
3959 | - if err != nil { |
3960 | - level.Error(logger).Log("msg", "Failed to compile receiver regex", "err", err) |
3961 | - return alertgroup_ops. |
3962 | - NewGetAlertGroupsBadRequest(). |
3963 | - WithPayload( |
3964 | - fmt.Sprintf("failed to parse receiver param: %v", err.Error()), |
3965 | - ) |
3966 | - } |
3967 | - } |
3968 | - |
3969 | - rf := func(receiverFilter *regexp.Regexp) func(r *dispatch.Route) bool { |
3970 | - return func(r *dispatch.Route) bool { |
3971 | - receiver := r.RouteOpts.Receiver |
3972 | - if receiverFilter != nil && !receiverFilter.MatchString(receiver) { |
3973 | - return false |
3974 | - } |
3975 | - return true |
3976 | - } |
3977 | - }(receiverFilter) |
3978 | - |
3979 | - af := api.alertFilter(matchers, *params.Silenced, *params.Inhibited, *params.Active) |
3980 | - alertGroups, allReceivers := api.alertGroups(rf, af) |
3981 | - |
3982 | - res := make(open_api_models.AlertGroups, 0, len(alertGroups)) |
3983 | - |
3984 | - for _, alertGroup := range alertGroups { |
3985 | - ag := &open_api_models.AlertGroup{ |
3986 | - Receiver: &open_api_models.Receiver{Name: &alertGroup.Receiver}, |
3987 | - Labels: modelLabelSetToAPILabelSet(alertGroup.Labels), |
3988 | - Alerts: make([]*open_api_models.GettableAlert, 0, len(alertGroup.Alerts)), |
3989 | - } |
3990 | - |
3991 | - for _, alert := range alertGroup.Alerts { |
3992 | - fp := alert.Fingerprint() |
3993 | - receivers := allReceivers[fp] |
3994 | - status := api.getAlertStatus(fp) |
3995 | - apiAlert := alertToOpenAPIAlert(alert, status, receivers) |
3996 | - ag.Alerts = append(ag.Alerts, apiAlert) |
3997 | - } |
3998 | - res = append(res, ag) |
3999 | - } |
4000 | - |
4001 | - return alertgroup_ops.NewGetAlertGroupsOK().WithPayload(res) |
4002 | -} |
4003 | - |
4004 | -func (api *API) alertFilter(matchers []*labels.Matcher, silenced, inhibited, active bool) func(a *types.Alert, now time.Time) bool { |
4005 | - return func(a *types.Alert, now time.Time) bool { |
4006 | - if !a.EndsAt.IsZero() && a.EndsAt.Before(now) { |
4007 | - return false |
4008 | - } |
4009 | - |
4010 | - // Set alert's current status based on its label set. |
4011 | - api.setAlertStatus(a.Labels) |
4012 | - |
4013 | - // Get alert's current status after seeing if it is suppressed. |
4014 | - status := api.getAlertStatus(a.Fingerprint()) |
4015 | - |
4016 | - if !active && status.State == types.AlertStateActive { |
4017 | - return false |
4018 | - } |
4019 | - |
4020 | - if !silenced && len(status.SilencedBy) != 0 { |
4021 | - return false |
4022 | - } |
4023 | - |
4024 | - if !inhibited && len(status.InhibitedBy) != 0 { |
4025 | - return false |
4026 | - } |
4027 | - |
4028 | - return alertMatchesFilterLabels(&a.Alert, matchers) |
4029 | - } |
4030 | -} |
4031 | - |
4032 | -func alertToOpenAPIAlert(alert *types.Alert, status types.AlertStatus, receivers []string) *open_api_models.GettableAlert { |
4033 | - startsAt := strfmt.DateTime(alert.StartsAt) |
4034 | - updatedAt := strfmt.DateTime(alert.UpdatedAt) |
4035 | - endsAt := strfmt.DateTime(alert.EndsAt) |
4036 | - |
4037 | - apiReceivers := make([]*open_api_models.Receiver, 0, len(receivers)) |
4038 | - for i := range receivers { |
4039 | - apiReceivers = append(apiReceivers, &open_api_models.Receiver{Name: &receivers[i]}) |
4040 | - } |
4041 | - |
4042 | - fp := alert.Fingerprint().String() |
4043 | - state := string(status.State) |
4044 | - aa := &open_api_models.GettableAlert{ |
4045 | - Alert: open_api_models.Alert{ |
4046 | - GeneratorURL: strfmt.URI(alert.GeneratorURL), |
4047 | - Labels: modelLabelSetToAPILabelSet(alert.Labels), |
4048 | - }, |
4049 | - Annotations: modelLabelSetToAPILabelSet(alert.Annotations), |
4050 | - StartsAt: &startsAt, |
4051 | - UpdatedAt: &updatedAt, |
4052 | - EndsAt: &endsAt, |
4053 | - Fingerprint: &fp, |
4054 | - Receivers: apiReceivers, |
4055 | - Status: &open_api_models.AlertStatus{ |
4056 | - State: &state, |
4057 | - SilencedBy: status.SilencedBy, |
4058 | - InhibitedBy: status.InhibitedBy, |
4059 | - }, |
4060 | - } |
4061 | - |
4062 | - if aa.Status.SilencedBy == nil { |
4063 | - aa.Status.SilencedBy = []string{} |
4064 | - } |
4065 | - |
4066 | - if aa.Status.InhibitedBy == nil { |
4067 | - aa.Status.InhibitedBy = []string{} |
4068 | - } |
4069 | - |
4070 | - return aa |
4071 | -} |
4072 | - |
4073 | -func openAPIAlertsToAlerts(apiAlerts open_api_models.PostableAlerts) []*types.Alert { |
4074 | - alerts := []*types.Alert{} |
4075 | - for _, apiAlert := range apiAlerts { |
4076 | - alert := types.Alert{ |
4077 | - Alert: prometheus_model.Alert{ |
4078 | - Labels: apiLabelSetToModelLabelSet(apiAlert.Labels), |
4079 | - Annotations: apiLabelSetToModelLabelSet(apiAlert.Annotations), |
4080 | - StartsAt: time.Time(apiAlert.StartsAt), |
4081 | - EndsAt: time.Time(apiAlert.EndsAt), |
4082 | - GeneratorURL: string(apiAlert.GeneratorURL), |
4083 | - }, |
4084 | - } |
4085 | - alerts = append(alerts, &alert) |
4086 | - } |
4087 | - |
4088 | - return alerts |
4089 | -} |
4090 | - |
4091 | -func removeEmptyLabels(ls prometheus_model.LabelSet) { |
4092 | - for k, v := range ls { |
4093 | - if string(v) == "" { |
4094 | - delete(ls, k) |
4095 | - } |
4096 | - } |
4097 | -} |
4098 | - |
4099 | -func modelLabelSetToAPILabelSet(modelLabelSet prometheus_model.LabelSet) open_api_models.LabelSet { |
4100 | - apiLabelSet := open_api_models.LabelSet{} |
4101 | - for key, value := range modelLabelSet { |
4102 | - apiLabelSet[string(key)] = string(value) |
4103 | - } |
4104 | - |
4105 | - return apiLabelSet |
4106 | -} |
4107 | - |
4108 | -func apiLabelSetToModelLabelSet(apiLabelSet open_api_models.LabelSet) prometheus_model.LabelSet { |
4109 | - modelLabelSet := prometheus_model.LabelSet{} |
4110 | - for key, value := range apiLabelSet { |
4111 | - modelLabelSet[prometheus_model.LabelName(key)] = prometheus_model.LabelValue(value) |
4112 | - } |
4113 | - |
4114 | - return modelLabelSet |
4115 | -} |
4116 | - |
4117 | -func receiversMatchFilter(receivers []string, filter *regexp.Regexp) bool { |
4118 | - for _, r := range receivers { |
4119 | - if filter.MatchString(r) { |
4120 | - return true |
4121 | - } |
4122 | - } |
4123 | - |
4124 | - return false |
4125 | -} |
4126 | - |
4127 | -func alertMatchesFilterLabels(a *prometheus_model.Alert, matchers []*labels.Matcher) bool { |
4128 | - sms := make(map[string]string) |
4129 | - for name, value := range a.Labels { |
4130 | - sms[string(name)] = string(value) |
4131 | - } |
4132 | - return matchFilterLabels(matchers, sms) |
4133 | -} |
4134 | - |
4135 | -func matchFilterLabels(matchers []*labels.Matcher, sms map[string]string) bool { |
4136 | - for _, m := range matchers { |
4137 | - v, prs := sms[m.Name] |
4138 | - switch m.Type { |
4139 | - case labels.MatchNotRegexp, labels.MatchNotEqual: |
4140 | - if m.Value == "" && prs { |
4141 | - continue |
4142 | - } |
4143 | - if !m.Matches(v) { |
4144 | - return false |
4145 | - } |
4146 | - default: |
4147 | - if m.Value == "" && !prs { |
4148 | - continue |
4149 | - } |
4150 | - if !prs || !m.Matches(v) { |
4151 | - return false |
4152 | - } |
4153 | - } |
4154 | - } |
4155 | - |
4156 | - return true |
4157 | -} |
4158 | - |
4159 | -func (api *API) getSilencesHandler(params silence_ops.GetSilencesParams) middleware.Responder { |
4160 | - logger := api.requestLogger(params.HTTPRequest) |
4161 | - |
4162 | - matchers := []*labels.Matcher{} |
4163 | - if params.Filter != nil { |
4164 | - for _, matcherString := range params.Filter { |
4165 | - matcher, err := labels.ParseMatcher(matcherString) |
4166 | - if err != nil { |
4167 | - level.Error(logger).Log("msg", "Failed to parse matchers", "err", err) |
4168 | - return alert_ops.NewGetAlertsBadRequest().WithPayload(err.Error()) |
4169 | - } |
4170 | - |
4171 | - matchers = append(matchers, matcher) |
4172 | - } |
4173 | - } |
4174 | - |
4175 | - psils, _, err := api.silences.Query() |
4176 | - if err != nil { |
4177 | - level.Error(logger).Log("msg", "Failed to get silences", "err", err) |
4178 | - return silence_ops.NewGetSilencesInternalServerError().WithPayload(err.Error()) |
4179 | - } |
4180 | - |
4181 | - sils := open_api_models.GettableSilences{} |
4182 | - for _, ps := range psils { |
4183 | - silence, err := gettableSilenceFromProto(ps) |
4184 | - if err != nil { |
4185 | - level.Error(logger).Log("msg", "Failed to unmarshal silence from proto", "err", err) |
4186 | - return silence_ops.NewGetSilencesInternalServerError().WithPayload(err.Error()) |
4187 | - } |
4188 | - if !gettableSilenceMatchesFilterLabels(silence, matchers) { |
4189 | - continue |
4190 | - } |
4191 | - sils = append(sils, &silence) |
4192 | - } |
4193 | - |
4194 | - sortSilences(sils) |
4195 | - |
4196 | - return silence_ops.NewGetSilencesOK().WithPayload(sils) |
4197 | -} |
4198 | - |
4199 | -var ( |
4200 | - silenceStateOrder = map[types.SilenceState]int{ |
4201 | - types.SilenceStateActive: 1, |
4202 | - types.SilenceStatePending: 2, |
4203 | - types.SilenceStateExpired: 3, |
4204 | - } |
4205 | -) |
4206 | - |
4207 | -// sortSilences sorts first according to the state "active, pending, expired" |
4208 | -// then by end time or start time depending on the state. |
4209 | -// active silences should show the next to expire first |
4210 | -// pending silences are ordered based on which one starts next |
4211 | -// expired are ordered based on which one expired most recently |
4212 | -func sortSilences(sils open_api_models.GettableSilences) { |
4213 | - sort.Slice(sils, func(i, j int) bool { |
4214 | - state1 := types.SilenceState(*sils[i].Status.State) |
4215 | - state2 := types.SilenceState(*sils[j].Status.State) |
4216 | - if state1 != state2 { |
4217 | - return silenceStateOrder[state1] < silenceStateOrder[state2] |
4218 | - } |
4219 | - switch state1 { |
4220 | - case types.SilenceStateActive: |
4221 | - endsAt1 := time.Time(*sils[i].Silence.EndsAt) |
4222 | - endsAt2 := time.Time(*sils[j].Silence.EndsAt) |
4223 | - return endsAt1.Before(endsAt2) |
4224 | - case types.SilenceStatePending: |
4225 | - startsAt1 := time.Time(*sils[i].Silence.StartsAt) |
4226 | - startsAt2 := time.Time(*sils[j].Silence.StartsAt) |
4227 | - return startsAt1.Before(startsAt2) |
4228 | - case types.SilenceStateExpired: |
4229 | - endsAt1 := time.Time(*sils[i].Silence.EndsAt) |
4230 | - endsAt2 := time.Time(*sils[j].Silence.EndsAt) |
4231 | - return endsAt1.After(endsAt2) |
4232 | - } |
4233 | - return false |
4234 | - }) |
4235 | -} |
4236 | - |
4237 | -func gettableSilenceMatchesFilterLabels(s open_api_models.GettableSilence, matchers []*labels.Matcher) bool { |
4238 | - sms := make(map[string]string) |
4239 | - for _, m := range s.Matchers { |
4240 | - sms[*m.Name] = *m.Value |
4241 | - } |
4242 | - |
4243 | - return matchFilterLabels(matchers, sms) |
4244 | -} |
4245 | - |
4246 | -func (api *API) getSilenceHandler(params silence_ops.GetSilenceParams) middleware.Responder { |
4247 | - logger := api.requestLogger(params.HTTPRequest) |
4248 | - |
4249 | - sils, _, err := api.silences.Query(silence.QIDs(params.SilenceID.String())) |
4250 | - if err != nil { |
4251 | - level.Error(logger).Log("msg", "Failed to get silence by id", "err", err, "id", params.SilenceID.String()) |
4252 | - return silence_ops.NewGetSilenceInternalServerError().WithPayload(err.Error()) |
4253 | - } |
4254 | - |
4255 | - if len(sils) == 0 { |
4256 | - level.Error(logger).Log("msg", "Failed to find silence", "err", err, "id", params.SilenceID.String()) |
4257 | - return silence_ops.NewGetSilenceNotFound() |
4258 | - } |
4259 | - |
4260 | - sil, err := gettableSilenceFromProto(sils[0]) |
4261 | - if err != nil { |
4262 | - level.Error(logger).Log("msg", "Failed to convert unmarshal from proto", "err", err) |
4263 | - return silence_ops.NewGetSilenceInternalServerError().WithPayload(err.Error()) |
4264 | - } |
4265 | - |
4266 | - return silence_ops.NewGetSilenceOK().WithPayload(&sil) |
4267 | -} |
4268 | - |
4269 | -func (api *API) deleteSilenceHandler(params silence_ops.DeleteSilenceParams) middleware.Responder { |
4270 | - logger := api.requestLogger(params.HTTPRequest) |
4271 | - |
4272 | - sid := params.SilenceID.String() |
4273 | - if err := api.silences.Expire(sid); err != nil { |
4274 | - level.Error(logger).Log("msg", "Failed to expire silence", "err", err) |
4275 | - return silence_ops.NewDeleteSilenceInternalServerError().WithPayload(err.Error()) |
4276 | - } |
4277 | - return silence_ops.NewDeleteSilenceOK() |
4278 | -} |
4279 | - |
4280 | -func gettableSilenceFromProto(s *silencepb.Silence) (open_api_models.GettableSilence, error) { |
4281 | - start := strfmt.DateTime(s.StartsAt) |
4282 | - end := strfmt.DateTime(s.EndsAt) |
4283 | - updated := strfmt.DateTime(s.UpdatedAt) |
4284 | - state := string(types.CalcSilenceState(s.StartsAt, s.EndsAt)) |
4285 | - sil := open_api_models.GettableSilence{ |
4286 | - Silence: open_api_models.Silence{ |
4287 | - StartsAt: &start, |
4288 | - EndsAt: &end, |
4289 | - Comment: &s.Comment, |
4290 | - CreatedBy: &s.CreatedBy, |
4291 | - }, |
4292 | - ID: &s.Id, |
4293 | - UpdatedAt: &updated, |
4294 | - Status: &open_api_models.SilenceStatus{ |
4295 | - State: &state, |
4296 | - }, |
4297 | - } |
4298 | - |
4299 | - for _, m := range s.Matchers { |
4300 | - matcher := &open_api_models.Matcher{ |
4301 | - Name: &m.Name, |
4302 | - Value: &m.Pattern, |
4303 | - } |
4304 | - switch m.Type { |
4305 | - case silencepb.Matcher_EQUAL: |
4306 | - f := false |
4307 | - matcher.IsRegex = &f |
4308 | - case silencepb.Matcher_REGEXP: |
4309 | - t := true |
4310 | - matcher.IsRegex = &t |
4311 | - default: |
4312 | - return sil, fmt.Errorf( |
4313 | - "unknown matcher type for matcher '%v' in silence '%v'", |
4314 | - m.Name, |
4315 | - s.Id, |
4316 | - ) |
4317 | - } |
4318 | - sil.Matchers = append(sil.Matchers, matcher) |
4319 | - } |
4320 | - |
4321 | - return sil, nil |
4322 | -} |
4323 | - |
4324 | -func (api *API) postSilencesHandler(params silence_ops.PostSilencesParams) middleware.Responder { |
4325 | - logger := api.requestLogger(params.HTTPRequest) |
4326 | - |
4327 | - sil, err := postableSilenceToProto(params.Silence) |
4328 | - if err != nil { |
4329 | - level.Error(logger).Log("msg", "Failed to marshal silence to proto", "err", err) |
4330 | - return silence_ops.NewPostSilencesBadRequest().WithPayload( |
4331 | - fmt.Sprintf("failed to convert API silence to internal silence: %v", err.Error()), |
4332 | - ) |
4333 | - } |
4334 | - |
4335 | - if sil.StartsAt.After(sil.EndsAt) || sil.StartsAt.Equal(sil.EndsAt) { |
4336 | - msg := "Failed to create silence: start time must be before end time" |
4337 | - level.Error(logger).Log("msg", msg, "starts_at", sil.StartsAt, "ends_at", sil.EndsAt) |
4338 | - return silence_ops.NewPostSilencesBadRequest().WithPayload(msg) |
4339 | - } |
4340 | - |
4341 | - if sil.EndsAt.Before(time.Now()) { |
4342 | - msg := "Failed to create silence: end time can't be in the past" |
4343 | - level.Error(logger).Log("msg", msg, "ends_at", sil.EndsAt) |
4344 | - return silence_ops.NewPostSilencesBadRequest().WithPayload(msg) |
4345 | - } |
4346 | - |
4347 | - sid, err := api.silences.Set(sil) |
4348 | - if err != nil { |
4349 | - level.Error(logger).Log("msg", "Failed to create silence", "err", err) |
4350 | - if err == silence.ErrNotFound { |
4351 | - return silence_ops.NewPostSilencesNotFound().WithPayload(err.Error()) |
4352 | - } |
4353 | - return silence_ops.NewPostSilencesBadRequest().WithPayload(err.Error()) |
4354 | - } |
4355 | - |
4356 | - return silence_ops.NewPostSilencesOK().WithPayload(&silence_ops.PostSilencesOKBody{ |
4357 | - SilenceID: sid, |
4358 | - }) |
4359 | -} |
4360 | - |
4361 | -func postableSilenceToProto(s *open_api_models.PostableSilence) (*silencepb.Silence, error) { |
4362 | - sil := &silencepb.Silence{ |
4363 | - Id: s.ID, |
4364 | - StartsAt: time.Time(*s.StartsAt), |
4365 | - EndsAt: time.Time(*s.EndsAt), |
4366 | - Comment: *s.Comment, |
4367 | - CreatedBy: *s.CreatedBy, |
4368 | - } |
4369 | - for _, m := range s.Matchers { |
4370 | - matcher := &silencepb.Matcher{ |
4371 | - Name: *m.Name, |
4372 | - Pattern: *m.Value, |
4373 | - Type: silencepb.Matcher_EQUAL, |
4374 | - } |
4375 | - if *m.IsRegex { |
4376 | - matcher.Type = silencepb.Matcher_REGEXP |
4377 | - } |
4378 | - sil.Matchers = append(sil.Matchers, matcher) |
4379 | - } |
4380 | - return sil, nil |
4381 | -} |
4382 | - |
4383 | -func parseFilter(filter []string) ([]*labels.Matcher, error) { |
4384 | - matchers := make([]*labels.Matcher, 0, len(filter)) |
4385 | - for _, matcherString := range filter { |
4386 | - matcher, err := labels.ParseMatcher(matcherString) |
4387 | - if err != nil { |
4388 | - return nil, err |
4389 | - } |
4390 | - |
4391 | - matchers = append(matchers, matcher) |
4392 | - } |
4393 | - return matchers, nil |
4394 | -} |
4395 | diff --git a/api/v2/api_test.go b/api/v2/api_test.go |
4396 | deleted file mode 100644 |
4397 | index 4cb4b74..0000000 |
4398 | --- a/api/v2/api_test.go |
4399 | +++ /dev/null |
4400 | @@ -1,173 +0,0 @@ |
4401 | -// Copyright 2019 Prometheus Team |
4402 | -// Licensed under the Apache License, Version 2.0 (the "License"); |
4403 | -// you may not use this file except in compliance with the License. |
4404 | -// You may obtain a copy of the License at |
4405 | -// |
4406 | -// http://www.apache.org/licenses/LICENSE-2.0 |
4407 | -// |
4408 | -// Unless required by applicable law or agreed to in writing, software |
4409 | -// distributed under the License is distributed on an "AS IS" BASIS, |
4410 | -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
4411 | -// See the License for the specific language governing permissions and |
4412 | -// limitations under the License. |
4413 | - |
4414 | -package v2 |
4415 | - |
4416 | -import ( |
4417 | - "strconv" |
4418 | - "testing" |
4419 | - "time" |
4420 | - |
4421 | - "github.com/go-openapi/strfmt" |
4422 | - "github.com/prometheus/common/model" |
4423 | - "github.com/stretchr/testify/require" |
4424 | - |
4425 | - open_api_models "github.com/prometheus/alertmanager/api/v2/models" |
4426 | - general_ops "github.com/prometheus/alertmanager/api/v2/restapi/operations/general" |
4427 | - "github.com/prometheus/alertmanager/config" |
4428 | - "github.com/prometheus/alertmanager/types" |
4429 | -) |
4430 | - |
4431 | -// If api.peers == nil, Alertmanager cluster feature is disabled. Make sure to |
4432 | -// not try to access properties of peer, which would trigger a nil pointer |
4433 | -// dereference. |
4434 | -func TestGetStatusHandlerWithNilPeer(t *testing.T) { |
4435 | - api := API{ |
4436 | - uptime: time.Now(), |
4437 | - peer: nil, |
4438 | - alertmanagerConfig: &config.Config{}, |
4439 | - } |
4440 | - |
4441 | - // Test ensures this method call does not panic. |
4442 | - status := api.getStatusHandler(general_ops.GetStatusParams{}).(*general_ops.GetStatusOK) |
4443 | - |
4444 | - c := status.Payload.Cluster |
4445 | - |
4446 | - if c == nil || c.Status == nil { |
4447 | - t.Fatal("expected cluster status not to be nil, violating the openapi specification") |
4448 | - } |
4449 | - |
4450 | - if c.Peers == nil { |
4451 | - t.Fatal("expected cluster peers to be not nil when api.peer is nil, violating the openapi specification") |
4452 | - } |
4453 | - if len(c.Peers) != 0 { |
4454 | - t.Fatal("expected cluster peers to be empty when api.peer is nil, violating the openapi specification") |
4455 | - } |
4456 | - |
4457 | - if c.Name != "" { |
4458 | - t.Fatal("expected cluster name to be empty, violating the openapi specification") |
4459 | - } |
4460 | -} |
4461 | - |
4462 | -func assertEqualStrings(t *testing.T, expected string, actual string) { |
4463 | - if expected != actual { |
4464 | - t.Fatal("expected: ", expected, ", actual: ", actual) |
4465 | - } |
4466 | -} |
4467 | - |
4468 | -var ( |
4469 | - testComment = "comment" |
4470 | - createdBy = "test" |
4471 | -) |
4472 | - |
4473 | -func gettableSilence(id string, state string, |
4474 | - updatedAt string, start string, end string, |
4475 | -) *open_api_models.GettableSilence { |
4476 | - |
4477 | - updAt, err := strfmt.ParseDateTime(updatedAt) |
4478 | - if err != nil { |
4479 | - panic(err) |
4480 | - } |
4481 | - strAt, err := strfmt.ParseDateTime(start) |
4482 | - if err != nil { |
4483 | - panic(err) |
4484 | - } |
4485 | - endAt, err := strfmt.ParseDateTime(end) |
4486 | - if err != nil { |
4487 | - panic(err) |
4488 | - } |
4489 | - return &open_api_models.GettableSilence{ |
4490 | - Silence: open_api_models.Silence{ |
4491 | - StartsAt: &strAt, |
4492 | - EndsAt: &endAt, |
4493 | - Comment: &testComment, |
4494 | - CreatedBy: &createdBy, |
4495 | - }, |
4496 | - ID: &id, |
4497 | - UpdatedAt: &updAt, |
4498 | - Status: &open_api_models.SilenceStatus{ |
4499 | - State: &state, |
4500 | - }, |
4501 | - } |
4502 | -} |
4503 | - |
4504 | -func TestGetSilencesHandler(t *testing.T) { |
4505 | - |
4506 | - updateTime := "2019-01-01T12:00:00+00:00" |
4507 | - silences := []*open_api_models.GettableSilence{ |
4508 | - gettableSilence("silence-6-expired", "expired", updateTime, |
4509 | - "2019-01-01T12:00:00+00:00", "2019-01-01T11:00:00+00:00"), |
4510 | - gettableSilence("silence-1-active", "active", updateTime, |
4511 | - "2019-01-01T12:00:00+00:00", "2019-01-01T13:00:00+00:00"), |
4512 | - gettableSilence("silence-7-expired", "expired", updateTime, |
4513 | - "2019-01-01T12:00:00+00:00", "2019-01-01T10:00:00+00:00"), |
4514 | - gettableSilence("silence-5-expired", "expired", updateTime, |
4515 | - "2019-01-01T12:00:00+00:00", "2019-01-01T12:00:00+00:00"), |
4516 | - gettableSilence("silence-0-active", "active", updateTime, |
4517 | - "2019-01-01T12:00:00+00:00", "2019-01-01T12:00:00+00:00"), |
4518 | - gettableSilence("silence-4-pending", "pending", updateTime, |
4519 | - "2019-01-01T13:00:00+00:00", "2019-01-01T12:00:00+00:00"), |
4520 | - gettableSilence("silence-3-pending", "pending", updateTime, |
4521 | - "2019-01-01T12:00:00+00:00", "2019-01-01T12:00:00+00:00"), |
4522 | - gettableSilence("silence-2-active", "active", updateTime, |
4523 | - "2019-01-01T12:00:00+00:00", "2019-01-01T14:00:00+00:00"), |
4524 | - } |
4525 | - sortSilences(open_api_models.GettableSilences(silences)) |
4526 | - |
4527 | - for i, sil := range silences { |
4528 | - assertEqualStrings(t, "silence-"+strconv.Itoa(i)+"-"+*sil.Status.State, *sil.ID) |
4529 | - } |
4530 | -} |
4531 | - |
4532 | -func convertDateTime(ts time.Time) *strfmt.DateTime { |
4533 | - dt := strfmt.DateTime(ts) |
4534 | - return &dt |
4535 | -} |
4536 | - |
4537 | -func TestAlertToOpenAPIAlert(t *testing.T) { |
4538 | - var ( |
4539 | - start = time.Now().Add(-time.Minute) |
4540 | - updated = time.Now() |
4541 | - active = "active" |
4542 | - fp = "0223b772b51c29e1" |
4543 | - receivers = []string{"receiver1", "receiver2"} |
4544 | - |
4545 | - alert = &types.Alert{ |
4546 | - Alert: model.Alert{ |
4547 | - Labels: model.LabelSet{"severity": "critical", "alertname": "alert1"}, |
4548 | - StartsAt: start, |
4549 | - }, |
4550 | - UpdatedAt: updated, |
4551 | - } |
4552 | - ) |
4553 | - openAPIAlert := alertToOpenAPIAlert(alert, types.AlertStatus{State: types.AlertStateActive}, receivers) |
4554 | - require.Equal(t, &open_api_models.GettableAlert{ |
4555 | - Annotations: open_api_models.LabelSet{}, |
4556 | - Alert: open_api_models.Alert{ |
4557 | - Labels: open_api_models.LabelSet{"severity": "critical", "alertname": "alert1"}, |
4558 | - }, |
4559 | - Status: &open_api_models.AlertStatus{ |
4560 | - State: &active, |
4561 | - InhibitedBy: []string{}, |
4562 | - SilencedBy: []string{}, |
4563 | - }, |
4564 | - StartsAt: convertDateTime(start), |
4565 | - EndsAt: convertDateTime(time.Time{}), |
4566 | - UpdatedAt: convertDateTime(updated), |
4567 | - Fingerprint: &fp, |
4568 | - Receivers: []*open_api_models.Receiver{ |
4569 | - &open_api_models.Receiver{Name: &receivers[0]}, |
4570 | - &open_api_models.Receiver{Name: &receivers[1]}, |
4571 | - }, |
4572 | - }, openAPIAlert) |
4573 | -} |
4574 | diff --git a/api/v2/client/alert/alert_client.go b/api/v2/client/alert/alert_client.go |
4575 | deleted file mode 100644 |
4576 | index 7d299c4..0000000 |
4577 | --- a/api/v2/client/alert/alert_client.go |
4578 | +++ /dev/null |
4579 | @@ -1,114 +0,0 @@ |
4580 | -// Code generated by go-swagger; DO NOT EDIT. |
4581 | - |
4582 | -// Copyright Prometheus Team |
4583 | -// Licensed under the Apache License, Version 2.0 (the "License"); |
4584 | -// you may not use this file except in compliance with the License. |
4585 | -// You may obtain a copy of the License at |
4586 | -// |
4587 | -// http://www.apache.org/licenses/LICENSE-2.0 |
4588 | -// |
4589 | -// Unless required by applicable law or agreed to in writing, software |
4590 | -// distributed under the License is distributed on an "AS IS" BASIS, |
4591 | -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
4592 | -// See the License for the specific language governing permissions and |
4593 | -// limitations under the License. |
4594 | -// |
4595 | - |
4596 | -package alert |
4597 | - |
4598 | -// This file was generated by the swagger tool. |
4599 | -// Editing this file might prove futile when you re-run the swagger generate command |
4600 | - |
4601 | -import ( |
4602 | - "fmt" |
4603 | - |
4604 | - "github.com/go-openapi/runtime" |
4605 | - |
4606 | - strfmt "github.com/go-openapi/strfmt" |
4607 | -) |
4608 | - |
4609 | -// New creates a new alert API client. |
4610 | -func New(transport runtime.ClientTransport, formats strfmt.Registry) *Client { |
4611 | - return &Client{transport: transport, formats: formats} |
4612 | -} |
4613 | - |
4614 | -/* |
4615 | -Client for alert API |
4616 | -*/ |
4617 | -type Client struct { |
4618 | - transport runtime.ClientTransport |
4619 | - formats strfmt.Registry |
4620 | -} |
4621 | - |
4622 | -/* |
4623 | -GetAlerts Get a list of alerts |
4624 | -*/ |
4625 | -func (a *Client) GetAlerts(params *GetAlertsParams) (*GetAlertsOK, error) { |
4626 | - // TODO: Validate the params before sending |
4627 | - if params == nil { |
4628 | - params = NewGetAlertsParams() |
4629 | - } |
4630 | - |
4631 | - result, err := a.transport.Submit(&runtime.ClientOperation{ |
4632 | - ID: "getAlerts", |
4633 | - Method: "GET", |
4634 | - PathPattern: "/alerts", |
4635 | - ProducesMediaTypes: []string{"application/json"}, |
4636 | - ConsumesMediaTypes: []string{"application/json"}, |
4637 | - Schemes: []string{"http"}, |
4638 | - Params: params, |
4639 | - Reader: &GetAlertsReader{formats: a.formats}, |
4640 | - Context: params.Context, |
4641 | - Client: params.HTTPClient, |
4642 | - }) |
4643 | - if err != nil { |
4644 | - return nil, err |
4645 | - } |
4646 | - success, ok := result.(*GetAlertsOK) |
4647 | - if ok { |
4648 | - return success, nil |
4649 | - } |
4650 | - // unexpected success response |
4651 | - // safeguard: normally, absent a default response, unknown success responses return an error above: so this is a codegen issue |
4652 | - msg := fmt.Sprintf("unexpected success response for getAlerts: API contract not enforced by server. Client expected to get an error, but got: %T", result) |
4653 | - panic(msg) |
4654 | -} |
4655 | - |
4656 | -/* |
4657 | -PostAlerts Create new Alerts |
4658 | -*/ |
4659 | -func (a *Client) PostAlerts(params *PostAlertsParams) (*PostAlertsOK, error) { |
4660 | - // TODO: Validate the params before sending |
4661 | - if params == nil { |
4662 | - params = NewPostAlertsParams() |
4663 | - } |
4664 | - |
4665 | - result, err := a.transport.Submit(&runtime.ClientOperation{ |
4666 | - ID: "postAlerts", |
4667 | - Method: "POST", |
4668 | - PathPattern: "/alerts", |
4669 | - ProducesMediaTypes: []string{"application/json"}, |
4670 | - ConsumesMediaTypes: []string{"application/json"}, |
4671 | - Schemes: []string{"http"}, |
4672 | - Params: params, |
4673 | - Reader: &PostAlertsReader{formats: a.formats}, |
4674 | - Context: params.Context, |
4675 | - Client: params.HTTPClient, |
4676 | - }) |
4677 | - if err != nil { |
4678 | - return nil, err |
4679 | - } |
4680 | - success, ok := result.(*PostAlertsOK) |
4681 | - if ok { |
4682 | - return success, nil |
4683 | - } |
4684 | - // unexpected success response |
4685 | - // safeguard: normally, absent a default response, unknown success responses return an error above: so this is a codegen issue |
4686 | - msg := fmt.Sprintf("unexpected success response for postAlerts: API contract not enforced by server. Client expected to get an error, but got: %T", result) |
4687 | - panic(msg) |
4688 | -} |
4689 | - |
4690 | -// SetTransport changes the transport on the client |
4691 | -func (a *Client) SetTransport(transport runtime.ClientTransport) { |
4692 | - a.transport = transport |
4693 | -} |
4694 | diff --git a/api/v2/client/alert/get_alerts_parameters.go b/api/v2/client/alert/get_alerts_parameters.go |
4695 | deleted file mode 100644 |
4696 | index cba0387..0000000 |
4697 | --- a/api/v2/client/alert/get_alerts_parameters.go |
4698 | +++ /dev/null |
4699 | @@ -1,350 +0,0 @@ |
4700 | -// Code generated by go-swagger; DO NOT EDIT. |
4701 | - |
4702 | -// Copyright Prometheus Team |
4703 | -// Licensed under the Apache License, Version 2.0 (the "License"); |
4704 | -// you may not use this file except in compliance with the License. |
4705 | -// You may obtain a copy of the License at |
4706 | -// |
4707 | -// http://www.apache.org/licenses/LICENSE-2.0 |
4708 | -// |
4709 | -// Unless required by applicable law or agreed to in writing, software |
4710 | -// distributed under the License is distributed on an "AS IS" BASIS, |
4711 | -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
4712 | -// See the License for the specific language governing permissions and |
4713 | -// limitations under the License. |
4714 | -// |
4715 | - |
4716 | -package alert |
4717 | - |
4718 | -// This file was generated by the swagger tool. |
4719 | -// Editing this file might prove futile when you re-run the swagger generate command |
4720 | - |
4721 | -import ( |
4722 | - "context" |
4723 | - "net/http" |
4724 | - "time" |
4725 | - |
4726 | - "github.com/go-openapi/errors" |
4727 | - "github.com/go-openapi/runtime" |
4728 | - cr "github.com/go-openapi/runtime/client" |
4729 | - "github.com/go-openapi/swag" |
4730 | - |
4731 | - strfmt "github.com/go-openapi/strfmt" |
4732 | -) |
4733 | - |
4734 | -// NewGetAlertsParams creates a new GetAlertsParams object |
4735 | -// with the default values initialized. |
4736 | -func NewGetAlertsParams() *GetAlertsParams { |
4737 | - var ( |
4738 | - activeDefault = bool(true) |
4739 | - inhibitedDefault = bool(true) |
4740 | - silencedDefault = bool(true) |
4741 | - unprocessedDefault = bool(true) |
4742 | - ) |
4743 | - return &GetAlertsParams{ |
4744 | - Active: &activeDefault, |
4745 | - Inhibited: &inhibitedDefault, |
4746 | - Silenced: &silencedDefault, |
4747 | - Unprocessed: &unprocessedDefault, |
4748 | - |
4749 | - timeout: cr.DefaultTimeout, |
4750 | - } |
4751 | -} |
4752 | - |
4753 | -// NewGetAlertsParamsWithTimeout creates a new GetAlertsParams object |
4754 | -// with the default values initialized, and the ability to set a timeout on a request |
4755 | -func NewGetAlertsParamsWithTimeout(timeout time.Duration) *GetAlertsParams { |
4756 | - var ( |
4757 | - activeDefault = bool(true) |
4758 | - inhibitedDefault = bool(true) |
4759 | - silencedDefault = bool(true) |
4760 | - unprocessedDefault = bool(true) |
4761 | - ) |
4762 | - return &GetAlertsParams{ |
4763 | - Active: &activeDefault, |
4764 | - Inhibited: &inhibitedDefault, |
4765 | - Silenced: &silencedDefault, |
4766 | - Unprocessed: &unprocessedDefault, |
4767 | - |
4768 | - timeout: timeout, |
4769 | - } |
4770 | -} |
4771 | - |
4772 | -// NewGetAlertsParamsWithContext creates a new GetAlertsParams object |
4773 | -// with the default values initialized, and the ability to set a context for a request |
4774 | -func NewGetAlertsParamsWithContext(ctx context.Context) *GetAlertsParams { |
4775 | - var ( |
4776 | - activeDefault = bool(true) |
4777 | - inhibitedDefault = bool(true) |
4778 | - silencedDefault = bool(true) |
4779 | - unprocessedDefault = bool(true) |
4780 | - ) |
4781 | - return &GetAlertsParams{ |
4782 | - Active: &activeDefault, |
4783 | - Inhibited: &inhibitedDefault, |
4784 | - Silenced: &silencedDefault, |
4785 | - Unprocessed: &unprocessedDefault, |
4786 | - |
4787 | - Context: ctx, |
4788 | - } |
4789 | -} |
4790 | - |
4791 | -// NewGetAlertsParamsWithHTTPClient creates a new GetAlertsParams object |
4792 | -// with the default values initialized, and the ability to set a custom HTTPClient for a request |
4793 | -func NewGetAlertsParamsWithHTTPClient(client *http.Client) *GetAlertsParams { |
4794 | - var ( |
4795 | - activeDefault = bool(true) |
4796 | - inhibitedDefault = bool(true) |
4797 | - silencedDefault = bool(true) |
4798 | - unprocessedDefault = bool(true) |
4799 | - ) |
4800 | - return &GetAlertsParams{ |
4801 | - Active: &activeDefault, |
4802 | - Inhibited: &inhibitedDefault, |
4803 | - Silenced: &silencedDefault, |
4804 | - Unprocessed: &unprocessedDefault, |
4805 | - HTTPClient: client, |
4806 | - } |
4807 | -} |
4808 | - |
4809 | -/*GetAlertsParams contains all the parameters to send to the API endpoint |
4810 | -for the get alerts operation typically these are written to a http.Request |
4811 | -*/ |
4812 | -type GetAlertsParams struct { |
4813 | - |
4814 | - /*Active |
4815 | - Show active alerts |
4816 | - |
4817 | - */ |
4818 | - Active *bool |
4819 | - /*Filter |
4820 | - A list of matchers to filter alerts by |
4821 | - |
4822 | - */ |
4823 | - Filter []string |
4824 | - /*Inhibited |
4825 | - Show inhibited alerts |
4826 | - |
4827 | - */ |
4828 | - Inhibited *bool |
4829 | - /*Receiver |
4830 | - A regex matching receivers to filter alerts by |
4831 | - |
4832 | - */ |
4833 | - Receiver *string |
4834 | - /*Silenced |
4835 | - Show silenced alerts |
4836 | - |
4837 | - */ |
4838 | - Silenced *bool |
4839 | - /*Unprocessed |
4840 | - Show unprocessed alerts |
4841 | - |
4842 | - */ |
4843 | - Unprocessed *bool |
4844 | - |
4845 | - timeout time.Duration |
4846 | - Context context.Context |
4847 | - HTTPClient *http.Client |
4848 | -} |
4849 | - |
4850 | -// WithTimeout adds the timeout to the get alerts params |
4851 | -func (o *GetAlertsParams) WithTimeout(timeout time.Duration) *GetAlertsParams { |
4852 | - o.SetTimeout(timeout) |
4853 | - return o |
4854 | -} |
4855 | - |
4856 | -// SetTimeout adds the timeout to the get alerts params |
4857 | -func (o *GetAlertsParams) SetTimeout(timeout time.Duration) { |
4858 | - o.timeout = timeout |
4859 | -} |
4860 | - |
4861 | -// WithContext adds the context to the get alerts params |
4862 | -func (o *GetAlertsParams) WithContext(ctx context.Context) *GetAlertsParams { |
4863 | - o.SetContext(ctx) |
4864 | - return o |
4865 | -} |
4866 | - |
4867 | -// SetContext adds the context to the get alerts params |
4868 | -func (o *GetAlertsParams) SetContext(ctx context.Context) { |
4869 | - o.Context = ctx |
4870 | -} |
4871 | - |
4872 | -// WithHTTPClient adds the HTTPClient to the get alerts params |
4873 | -func (o *GetAlertsParams) WithHTTPClient(client *http.Client) *GetAlertsParams { |
4874 | - o.SetHTTPClient(client) |
4875 | - return o |
4876 | -} |
4877 | - |
4878 | -// SetHTTPClient adds the HTTPClient to the get alerts params |
4879 | -func (o *GetAlertsParams) SetHTTPClient(client *http.Client) { |
4880 | - o.HTTPClient = client |
4881 | -} |
4882 | - |
4883 | -// WithActive adds the active to the get alerts params |
4884 | -func (o *GetAlertsParams) WithActive(active *bool) *GetAlertsParams { |
4885 | - o.SetActive(active) |
4886 | - return o |
4887 | -} |
4888 | - |
4889 | -// SetActive adds the active to the get alerts params |
4890 | -func (o *GetAlertsParams) SetActive(active *bool) { |
4891 | - o.Active = active |
4892 | -} |
4893 | - |
4894 | -// WithFilter adds the filter to the get alerts params |
4895 | -func (o *GetAlertsParams) WithFilter(filter []string) *GetAlertsParams { |
4896 | - o.SetFilter(filter) |
4897 | - return o |
4898 | -} |
4899 | - |
4900 | -// SetFilter adds the filter to the get alerts params |
4901 | -func (o *GetAlertsParams) SetFilter(filter []string) { |
4902 | - o.Filter = filter |
4903 | -} |
4904 | - |
4905 | -// WithInhibited adds the inhibited to the get alerts params |
4906 | -func (o *GetAlertsParams) WithInhibited(inhibited *bool) *GetAlertsParams { |
4907 | - o.SetInhibited(inhibited) |
4908 | - return o |
4909 | -} |
4910 | - |
4911 | -// SetInhibited adds the inhibited to the get alerts params |
4912 | -func (o *GetAlertsParams) SetInhibited(inhibited *bool) { |
4913 | - o.Inhibited = inhibited |
4914 | -} |
4915 | - |
4916 | -// WithReceiver adds the receiver to the get alerts params |
4917 | -func (o *GetAlertsParams) WithReceiver(receiver *string) *GetAlertsParams { |
4918 | - o.SetReceiver(receiver) |
4919 | - return o |
4920 | -} |
4921 | - |
4922 | -// SetReceiver adds the receiver to the get alerts params |
4923 | -func (o *GetAlertsParams) SetReceiver(receiver *string) { |
4924 | - o.Receiver = receiver |
4925 | -} |
4926 | - |
4927 | -// WithSilenced adds the silenced to the get alerts params |
4928 | -func (o *GetAlertsParams) WithSilenced(silenced *bool) *GetAlertsParams { |
4929 | - o.SetSilenced(silenced) |
4930 | - return o |
4931 | -} |
4932 | - |
4933 | -// SetSilenced adds the silenced to the get alerts params |
4934 | -func (o *GetAlertsParams) SetSilenced(silenced *bool) { |
4935 | - o.Silenced = silenced |
4936 | -} |
4937 | - |
4938 | -// WithUnprocessed adds the unprocessed to the get alerts params |
4939 | -func (o *GetAlertsParams) WithUnprocessed(unprocessed *bool) *GetAlertsParams { |
4940 | - o.SetUnprocessed(unprocessed) |
4941 | - return o |
4942 | -} |
4943 | - |
4944 | -// SetUnprocessed adds the unprocessed to the get alerts params |
4945 | -func (o *GetAlertsParams) SetUnprocessed(unprocessed *bool) { |
4946 | - o.Unprocessed = unprocessed |
4947 | -} |
4948 | - |
4949 | -// WriteToRequest writes these params to a swagger request |
4950 | -func (o *GetAlertsParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error { |
4951 | - |
4952 | - if err := r.SetTimeout(o.timeout); err != nil { |
4953 | - return err |
4954 | - } |
4955 | - var res []error |
4956 | - |
4957 | - if o.Active != nil { |
4958 | - |
4959 | - // query param active |
4960 | - var qrActive bool |
4961 | - if o.Active != nil { |
4962 | - qrActive = *o.Active |
4963 | - } |
4964 | - qActive := swag.FormatBool(qrActive) |
4965 | - if qActive != "" { |
4966 | - if err := r.SetQueryParam("active", qActive); err != nil { |
4967 | - return err |
4968 | - } |
4969 | - } |
4970 | - |
4971 | - } |
4972 | - |
4973 | - valuesFilter := o.Filter |
4974 | - |
4975 | - joinedFilter := swag.JoinByFormat(valuesFilter, "multi") |
4976 | - // query array param filter |
4977 | - if err := r.SetQueryParam("filter", joinedFilter...); err != nil { |
4978 | - return err |
4979 | - } |
4980 | - |
4981 | - if o.Inhibited != nil { |
4982 | - |
4983 | - // query param inhibited |
4984 | - var qrInhibited bool |
4985 | - if o.Inhibited != nil { |
4986 | - qrInhibited = *o.Inhibited |
4987 | - } |
4988 | - qInhibited := swag.FormatBool(qrInhibited) |
4989 | - if qInhibited != "" { |
4990 | - if err := r.SetQueryParam("inhibited", qInhibited); err != nil { |
4991 | - return err |
4992 | - } |
4993 | - } |
4994 | - |
4995 | - } |
4996 | - |
4997 | - if o.Receiver != nil { |
4998 | - |
4999 | - // query param receiver |
5000 | - var qrReceiver string |
Asking for a review from Lucas because he reviewed the 21.04 related change.