mirror of
https://github.com/prymitive/karma
synced 2026-05-21 04:33:07 +00:00
fix(backend): remove silenceForm.author config section
This commit is contained in:
@@ -167,10 +167,6 @@ level=info msg=" comments:"
|
||||
level=info msg=" linkDetect:"
|
||||
level=info msg=" rules: []"
|
||||
level=info msg="silenceForm:"
|
||||
level=info msg=" author:"
|
||||
level=info msg=" populate_from_header:"
|
||||
level=info msg=" header: CF-RAY"
|
||||
level=info msg=" value_re: ^(.+)$"
|
||||
level=info msg=" strip:"
|
||||
level=info msg=" labels:"
|
||||
level=info msg=" - job"
|
||||
|
||||
@@ -128,10 +128,6 @@ silences:
|
||||
- regex: "(DEVOPS-[0-9]+)"
|
||||
uriTemplate: https://jira.example.com/browse/$1
|
||||
silenceForm:
|
||||
author:
|
||||
populate_from_header:
|
||||
header: "CF-RAY"
|
||||
value_re: "^(.+)$"
|
||||
strip:
|
||||
labels:
|
||||
- job
|
||||
@@ -406,10 +402,6 @@ level=info msg=" rules:"
|
||||
level=info msg=" - regex: (DEVOPS-[0-9]+)"
|
||||
level=info msg=" uriTemplate: https://jira.example.com/browse/$1"
|
||||
level=info msg="silenceForm:"
|
||||
level=info msg=" author:"
|
||||
level=info msg=" populate_from_header:"
|
||||
level=info msg=" header: CF-RAY"
|
||||
level=info msg=" value_re: ^(.+)$"
|
||||
level=info msg=" strip:"
|
||||
level=info msg=" labels:"
|
||||
level=info msg=" - job"
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
# Raises an error if silence form populate from header config is using invalid regex rule
|
||||
karma.bin-should-fail --log.format=text --log.config=false --log.level=error --config.file=karma.yaml
|
||||
! stdout .
|
||||
stderr 'msg="Invalid regex for silenceform.author.populate_from_header.value_re: error parsing regexp: invalid nested repetition operator: `\+\+`"'
|
||||
|
||||
-- karma.yaml --
|
||||
alertmanager:
|
||||
servers:
|
||||
- name: default
|
||||
uri: https://localhost:9093
|
||||
silenceForm:
|
||||
author:
|
||||
populate_from_header:
|
||||
header: "CF-RAY"
|
||||
value_re: ".++++"
|
||||
@@ -1,14 +0,0 @@
|
||||
# Raises an error if silence form populate from header config is missing header name
|
||||
karma.bin-should-fail --log.format=text --log.config=false --log.level=error --config.file=karma.yaml
|
||||
! stdout .
|
||||
stderr 'msg="silenceform.author.populate_from_header.header is required when silenceform.author.populate_from_header.value_re is set"'
|
||||
|
||||
-- karma.yaml --
|
||||
alertmanager:
|
||||
servers:
|
||||
- name: default
|
||||
uri: https://localhost:9093
|
||||
silenceForm:
|
||||
author:
|
||||
populate_from_header:
|
||||
value_re: "^(.+)$"
|
||||
@@ -1,14 +0,0 @@
|
||||
# Raises an error if silence form populate from header config is missing regex rule
|
||||
karma.bin-should-fail --log.format=text --log.config=false --log.level=error --config.file=karma.yaml
|
||||
! stdout .
|
||||
stderr 'msg="silenceform.author.populate_from_header.value_re is required when silenceform.author.populate_from_header.header is set"'
|
||||
|
||||
-- karma.yaml --
|
||||
alertmanager:
|
||||
servers:
|
||||
- name: default
|
||||
uri: https://localhost:9093
|
||||
silenceForm:
|
||||
author:
|
||||
populate_from_header:
|
||||
header: "CF-RAY"
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -122,21 +121,6 @@ func populateAPIFilters(matchFilters []filters.FilterT) []models.Filter {
|
||||
return apiFilters
|
||||
}
|
||||
|
||||
func authorFromHeader(c *gin.Context, header string, valueRe string) string {
|
||||
if header == "" || valueRe == "" {
|
||||
return ""
|
||||
}
|
||||
v := c.GetHeader(header)
|
||||
if v != "" {
|
||||
r := regexp.MustCompile(valueRe)
|
||||
matches := r.FindAllStringSubmatch(v, 1)
|
||||
if len(matches) > 0 && len(matches[0]) > 1 {
|
||||
return matches[0][1]
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// alerts endpoint, json, JS will query this via AJAX call
|
||||
func alerts(c *gin.Context) {
|
||||
noCache(c)
|
||||
@@ -168,7 +152,6 @@ func alerts(c *gin.Context) {
|
||||
AnnotationsHidden: config.Config.Annotations.Hidden,
|
||||
AnnotationsVisible: config.Config.Annotations.Visible,
|
||||
SilenceForm: models.SilenceFormSettings{
|
||||
Author: authorFromHeader(c, config.Config.SilenceForm.Author.PopulateFromHeader.Header, config.Config.SilenceForm.Author.PopulateFromHeader.ValueRegex),
|
||||
Strip: models.SilenceFormStripSettings{
|
||||
Labels: config.Config.SilenceForm.Strip.Labels,
|
||||
},
|
||||
|
||||
@@ -551,86 +551,6 @@ func TestGzipMiddlewareWithoutAcceptEncoding(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateAuthorFromHeaders(t *testing.T) {
|
||||
type testValidateAuthorFromHeaders struct {
|
||||
configHeader string
|
||||
configRegex string
|
||||
requestHeaderName string
|
||||
requestHeaderValue string
|
||||
expectedAuthor string
|
||||
}
|
||||
|
||||
testCases := []testValidateAuthorFromHeaders{
|
||||
{
|
||||
configHeader: "X-Auth",
|
||||
configRegex: "^(.*)$",
|
||||
requestHeaderName: "X-Auth",
|
||||
requestHeaderValue: "foo",
|
||||
expectedAuthor: "foo",
|
||||
},
|
||||
{
|
||||
configHeader: "X-Auth",
|
||||
configRegex: "^foo(.*)bar$",
|
||||
requestHeaderName: "X-Auth",
|
||||
requestHeaderValue: "foo123bar",
|
||||
expectedAuthor: "123",
|
||||
},
|
||||
{
|
||||
configHeader: "X-Auth",
|
||||
configRegex: "^(.*)$",
|
||||
requestHeaderName: "X-Auth-Not",
|
||||
requestHeaderValue: "foo",
|
||||
expectedAuthor: "",
|
||||
},
|
||||
{
|
||||
configHeader: "",
|
||||
configRegex: "^(.*)$",
|
||||
requestHeaderName: "X-Auth",
|
||||
requestHeaderValue: "foo",
|
||||
expectedAuthor: "",
|
||||
},
|
||||
{
|
||||
configHeader: "X-Auth",
|
||||
configRegex: "",
|
||||
requestHeaderName: "X-Auth",
|
||||
requestHeaderValue: "foo",
|
||||
expectedAuthor: "",
|
||||
},
|
||||
{
|
||||
configHeader: "X-Auth",
|
||||
configRegex: "^.*$",
|
||||
requestHeaderName: "X-Auth",
|
||||
requestHeaderValue: "foo",
|
||||
expectedAuthor: "",
|
||||
},
|
||||
}
|
||||
|
||||
mockConfig()
|
||||
for _, testCase := range testCases {
|
||||
config.Config.SilenceForm.Author.PopulateFromHeader.Header = testCase.configHeader
|
||||
config.Config.SilenceForm.Author.PopulateFromHeader.ValueRegex = testCase.configRegex
|
||||
|
||||
r := ginTestEngine()
|
||||
req := httptest.NewRequest("GET", "/alerts.json", nil)
|
||||
req.Header.Set(testCase.requestHeaderName, testCase.requestHeaderValue)
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
r.ServeHTTP(resp, req)
|
||||
if resp.Code != http.StatusOK {
|
||||
t.Errorf("GET /alerts.json returned status %d", resp.Code)
|
||||
}
|
||||
ur := models.AlertsResponse{}
|
||||
body := resp.Body.Bytes()
|
||||
err := json.Unmarshal(body, &ur)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to unmarshal response: %s", err)
|
||||
}
|
||||
if ur.Settings.SilenceForm.Author != testCase.expectedAuthor {
|
||||
t.Errorf("Expected author '%s', got '%s', test case: %+v", testCase.expectedAuthor, ur.Settings.SilenceForm.Author, testCase)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSilences(t *testing.T) {
|
||||
type silenceTestCase struct {
|
||||
searchTerm string
|
||||
@@ -804,7 +724,6 @@ func TestEmptySettings(t *testing.T) {
|
||||
Strip: models.SilenceFormStripSettings{
|
||||
Labels: []string{},
|
||||
},
|
||||
Author: "",
|
||||
},
|
||||
AlertAcknowledgement: models.AlertAcknowledgementSettings{
|
||||
Enabled: false,
|
||||
|
||||
@@ -75,10 +75,6 @@ silences:
|
||||
- regex: "(DEVOPS-[0-9]+)"
|
||||
uriTemplate: https://jira.example.com/browse/$1
|
||||
silenceForm:
|
||||
author:
|
||||
populate_from_header:
|
||||
header: "CF-RAY"
|
||||
value_re: "^(.+)$"
|
||||
strip:
|
||||
labels:
|
||||
- job
|
||||
|
||||
@@ -892,45 +892,24 @@ sentry:
|
||||
## Silence form
|
||||
|
||||
`silenceForm` section allows customizing silence form behavior.
|
||||
`author:populate_from_header` subsection allows to configure fetching of author
|
||||
name used on the silence form from the request header. It can be used with
|
||||
setups where karma is deployed behind authentication proxy that adds some extra
|
||||
headers with username for all requests received by karma.
|
||||
|
||||
Syntax:
|
||||
|
||||
```YAML
|
||||
silenceForm:
|
||||
author:
|
||||
populate_from_header:
|
||||
header: string
|
||||
value_re: string
|
||||
strip:
|
||||
labels: list of strings
|
||||
```
|
||||
|
||||
- `author:populate_from_header:header` - name of the header to read the username
|
||||
from
|
||||
- `author:populate_from_header:value_re` -
|
||||
[regex](https://golang.org/s/re2syntax) used to extract the username from the
|
||||
request header. It must include one numbered capturing group, whatever is
|
||||
matched by that group will be used as the silence form author field. Both
|
||||
`header` and `value_re` must be set for this feature to work.
|
||||
- `strip:labels` - list of labels to ignore when populating silence form from
|
||||
individual alerts or group of alerts. This allows to create silences matching
|
||||
only unique labels, like `instance` or `host`, ignoring any common labels like
|
||||
`job`.
|
||||
|
||||
Example where `job` label won't be auto populated onto the silence form and
|
||||
where the `X-Auth` header with value `User foobar` will set the default silence
|
||||
author to `foobar`.
|
||||
Example where `job` label won't be auto populated in the silence form.
|
||||
|
||||
```YAML
|
||||
silenceForm:
|
||||
author:
|
||||
populate_from_header:
|
||||
header: X-Auth
|
||||
value_re: ^User (.+)$
|
||||
strip:
|
||||
labels:
|
||||
- job
|
||||
|
||||
@@ -103,8 +103,6 @@ func SetupFlags(f *pflag.FlagSet) {
|
||||
"List of receivers to not display alerts for")
|
||||
|
||||
f.StringSlice("silenceform.strip.labels", []string{}, "List of labels to ignore when auto-filling silence form from alerts")
|
||||
f.String("silenceform.author.populate_from_header.header", "", "Header to read the default silence author from")
|
||||
f.String("silenceform.author.populate_from_header.value_re", "", "Header value regex to read the default silence author")
|
||||
|
||||
f.String("listen.address", "", "IP/Hostname to listen on")
|
||||
f.Int("listen.port", 8080, "HTTP port to listen on")
|
||||
@@ -291,18 +289,6 @@ func (config *configSchema) Read(flags *pflag.FlagSet) string {
|
||||
config.Authentication.Enabled = true
|
||||
}
|
||||
|
||||
if config.SilenceForm.Author.PopulateFromHeader.ValueRegex != "" {
|
||||
_, err = regexp.Compile(config.SilenceForm.Author.PopulateFromHeader.ValueRegex)
|
||||
if err != nil {
|
||||
log.Fatalf("Invalid regex for silenceform.author.populate_from_header.value_re: %s", err.Error())
|
||||
}
|
||||
if config.SilenceForm.Author.PopulateFromHeader.Header == "" {
|
||||
log.Fatalf("silenceform.author.populate_from_header.header is required when silenceform.author.populate_from_header.value_re is set")
|
||||
}
|
||||
} else if config.SilenceForm.Author.PopulateFromHeader.Header != "" {
|
||||
log.Fatalf("silenceform.author.populate_from_header.value_re is required when silenceform.author.populate_from_header.header is set")
|
||||
}
|
||||
|
||||
if !slices.StringInSlice([]string{"omit", "include", "same-origin"}, config.Alertmanager.CORS.Credentials) {
|
||||
log.Fatalf("Invalid alertmanager.cors.credentials value '%s', allowed options: omit, inclue, same-origin", config.Alertmanager.CORS.Credentials)
|
||||
}
|
||||
|
||||
@@ -109,10 +109,6 @@ silences:
|
||||
linkDetect:
|
||||
rules: []
|
||||
silenceForm:
|
||||
author:
|
||||
populate_from_header:
|
||||
header: ""
|
||||
value_re: ""
|
||||
strip:
|
||||
labels: []
|
||||
ui:
|
||||
@@ -255,25 +251,6 @@ func TestLogValues(t *testing.T) {
|
||||
Config.LogValues()
|
||||
}
|
||||
|
||||
func TestInvalidSilenceFormRegex(t *testing.T) {
|
||||
resetEnv()
|
||||
os.Setenv("SILENCEFORM_AUTHOR_POPULATE_FROM_HEADER_VALUE_RE", ".****")
|
||||
|
||||
log.SetLevel(log.PanicLevel)
|
||||
defer func() { log.StandardLogger().ExitFunc = nil }()
|
||||
var wasFatal bool
|
||||
log.StandardLogger().ExitFunc = func(int) { wasFatal = true }
|
||||
|
||||
mockConfigRead()
|
||||
|
||||
if Config.SilenceForm.Author.PopulateFromHeader.ValueRegex != ".****" {
|
||||
t.Errorf("Config.SilenceForm.Author.PopulateFromHeader.ValueRegex value is %q", Config.SilenceForm.Author.PopulateFromHeader.ValueRegex)
|
||||
}
|
||||
if !wasFatal {
|
||||
t.Error("Invalid silence form regex didn't cause log.Fatal()")
|
||||
}
|
||||
}
|
||||
|
||||
func TestInvalidGridSortingOrder(t *testing.T) {
|
||||
resetEnv()
|
||||
os.Setenv("GRID_SORTING_ORDER", "foo")
|
||||
|
||||
@@ -139,12 +139,6 @@ type configSchema struct {
|
||||
} `yaml:"comments"`
|
||||
} `yaml:"silences"`
|
||||
SilenceForm struct {
|
||||
Author struct {
|
||||
PopulateFromHeader struct {
|
||||
Header string `yaml:"header" koanf:"header"`
|
||||
ValueRegex string `yaml:"value_re" koanf:"value_re"`
|
||||
} `yaml:"populate_from_header" koanf:"populate_from_header"`
|
||||
} `yaml:"author"`
|
||||
Strip struct {
|
||||
Labels []string
|
||||
}
|
||||
|
||||
@@ -274,8 +274,7 @@ type SilenceFormStripSettings struct {
|
||||
}
|
||||
|
||||
type SilenceFormSettings struct {
|
||||
Strip SilenceFormStripSettings `json:"strip"`
|
||||
Author string `json:"author"`
|
||||
Strip SilenceFormStripSettings `json:"strip"`
|
||||
}
|
||||
|
||||
type AlertAcknowledgementSettings struct {
|
||||
|
||||
Reference in New Issue
Block a user