-
Notifications
You must be signed in to change notification settings - Fork 818
Added limit for size of configuration file that tenant can upload to Alertmanager. #4201
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 3 commits
b081a95
b67a535
556d019
4455019
18b5672
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,6 +3,7 @@ package alertmanager | |
import ( | ||
"context" | ||
"fmt" | ||
"io" | ||
"io/ioutil" | ||
"net/http" | ||
"os" | ||
|
@@ -32,6 +33,7 @@ const ( | |
errDeletingConfiguration = "unable to delete the Alertmanager config" | ||
errNoOrgID = "unable to determine the OrgID" | ||
errListAllUser = "unable to list the Alertmanager users" | ||
errConfigurationTooBig = "Alertmanager configuration is too big, limit: %d bytes" | ||
|
||
fetchConcurrency = 16 | ||
) | ||
|
@@ -98,13 +100,30 @@ func (am *MultitenantAlertmanager) SetUserConfig(w http.ResponseWriter, r *http. | |
return | ||
} | ||
|
||
payload, err := ioutil.ReadAll(r.Body) | ||
var input io.Reader | ||
maxConfigSize := am.limits.AlertmanagerMaxConfigSize(userID) | ||
if maxConfigSize > 0 { | ||
// LimitReader will return EOF after reading specified number of bytes. To check if | ||
// we have read too many bytes, allow one extra byte. | ||
input = io.LimitReader(r.Body, int64(maxConfigSize)+1) | ||
} else { | ||
input = r.Body | ||
} | ||
|
||
payload, err := ioutil.ReadAll(input) | ||
if err != nil { | ||
level.Error(logger).Log("msg", errReadingConfiguration, "err", err.Error()) | ||
http.Error(w, fmt.Sprintf("%s: %s", errReadingConfiguration, err.Error()), http.StatusBadRequest) | ||
return | ||
} | ||
|
||
if maxConfigSize > 0 && len(payload) > maxConfigSize { | ||
msg := fmt.Sprintf(errConfigurationTooBig, maxConfigSize) | ||
level.Error(logger).Log("msg", msg) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is not an actionable error on Cortex side, so I wouldn't use the error level. I would use Warn instead. |
||
http.Error(w, msg, http.StatusBadRequest) | ||
return | ||
} | ||
|
||
cfg := &UserConfig{} | ||
err = yaml.Unmarshal(payload, cfg) | ||
if err != nil { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -103,9 +103,10 @@ type Limits struct { | |
AlertmanagerReceiversBlockCIDRNetworks flagext.CIDRSliceCSV `yaml:"alertmanager_receivers_firewall_block_cidr_networks" json:"alertmanager_receivers_firewall_block_cidr_networks"` | ||
AlertmanagerReceiversBlockPrivateAddresses bool `yaml:"alertmanager_receivers_firewall_block_private_addresses" json:"alertmanager_receivers_firewall_block_private_addresses"` | ||
|
||
// Alertmanager limits | ||
NotificationRateLimit float64 `yaml:"alertmanager_notification_rate_limit" json:"alertmanager_notification_rate_limit"` | ||
NotificationRateLimitPerIntegration NotificationRateLimitMap `yaml:"alertmanager_notification_rate_limit_per_integration" json:"alertmanager_notification_rate_limit_per_integration"` | ||
|
||
AlertmanagerMaxConfigSize int `yaml:"alertmanager_max_config_size" json:"alertmanager_max_config_size"` | ||
} | ||
|
||
// RegisterFlags adds the flags required to config this to the given FlagSet | ||
|
@@ -173,6 +174,7 @@ func (l *Limits) RegisterFlags(f *flag.FlagSet) { | |
l.NotificationRateLimitPerIntegration = NotificationRateLimitMap{} | ||
} | ||
f.Var(&l.NotificationRateLimitPerIntegration, "alertmanager.notification-rate-limit-per-integration", "Per-integration notification rate limits. Value is a map, where each key is integration name and value is a rate-limit (float). On command line, this map is given in JSON format. Rate limit has the same meaning as -alertmanager.notification-rate-limit, but only applies for specific integration. Allowed integration names: "+strings.Join(allowedIntegrationNames, ", ")+".") | ||
f.IntVar(&l.AlertmanagerMaxConfigSize, "alertmanager.max-config-size", 0, "Maximum size of configuration file for Alertmanager that tenant can upload via Alertmanager API. 0 = no limit.") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [nit] I'm wondering if, to make it even more clear, we should mention it's in bytes. We can do it in the CLI flag description but I'm also wondering if we should add a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sounds good. I will update it. |
||
} | ||
|
||
// Validate the limits config and returns an error if the validation | ||
|
@@ -573,6 +575,10 @@ func (o *Overrides) NotificationBurstSize(user string, integration string) int { | |
return int(l) | ||
} | ||
|
||
func (o *Overrides) AlertmanagerMaxConfigSize(userID string) int { | ||
return o.getOverridesForUser(userID).AlertmanagerMaxConfigSize | ||
} | ||
|
||
func (o *Overrides) getOverridesForUser(userID string) *Limits { | ||
if o.tenantLimits != nil { | ||
l := o.tenantLimits.ByUserID(userID) | ||
|
Uh oh!
There was an error while loading. Please reload this page.