| 122 | } |
| 123 | |
| 124 | func (am *MultitenantAlertmanager) SetUserConfig(w http.ResponseWriter, r *http.Request) { |
| 125 | logger := util_log.WithContext(r.Context(), am.logger) |
| 126 | userID, err := users.TenantID(r.Context()) |
| 127 | if err != nil { |
| 128 | level.Error(logger).Log("msg", errNoOrgID, "err", err.Error()) |
| 129 | http.Error(w, fmt.Sprintf("%s: %s", errNoOrgID, err.Error()), http.StatusUnauthorized) |
| 130 | return |
| 131 | } |
| 132 | |
| 133 | var input io.Reader |
| 134 | maxConfigSize := am.limits.AlertmanagerMaxConfigSize(userID) |
| 135 | if maxConfigSize > 0 { |
| 136 | // LimitReader will return EOF after reading specified number of bytes. To check if |
| 137 | // we have read too many bytes, allow one extra byte. |
| 138 | input = io.LimitReader(r.Body, int64(maxConfigSize)+1) |
| 139 | } else { |
| 140 | input = r.Body |
| 141 | } |
| 142 | |
| 143 | payload, err := io.ReadAll(input) |
| 144 | if err != nil { |
| 145 | level.Error(logger).Log("msg", errReadingConfiguration, "err", err.Error()) |
| 146 | http.Error(w, fmt.Sprintf("%s: %s", errReadingConfiguration, err.Error()), http.StatusBadRequest) |
| 147 | return |
| 148 | } |
| 149 | |
| 150 | if maxConfigSize > 0 && len(payload) > maxConfigSize { |
| 151 | msg := fmt.Sprintf(errConfigurationTooBig, maxConfigSize) |
| 152 | level.Warn(logger).Log("msg", msg) |
| 153 | http.Error(w, msg, http.StatusBadRequest) |
| 154 | return |
| 155 | } |
| 156 | |
| 157 | cfg := &UserConfig{} |
| 158 | err = yaml.Unmarshal(payload, cfg) |
| 159 | if err != nil { |
| 160 | level.Error(logger).Log("msg", errMarshallingYAML, "err", err.Error()) |
| 161 | http.Error(w, fmt.Sprintf("%s: %s", errMarshallingYAML, err.Error()), http.StatusBadRequest) |
| 162 | return |
| 163 | } |
| 164 | |
| 165 | cfgDesc := alertspb.ToProto(cfg.AlertmanagerConfig, cfg.TemplateFiles, userID) |
| 166 | if err := validateUserConfig(logger, cfgDesc, am.limits, userID); err != nil { |
| 167 | level.Warn(logger).Log("msg", errValidatingConfig, "err", err.Error()) |
| 168 | http.Error(w, fmt.Sprintf("%s: %s", errValidatingConfig, err.Error()), http.StatusBadRequest) |
| 169 | return |
| 170 | } |
| 171 | |
| 172 | err = am.store.SetAlertConfig(r.Context(), cfgDesc) |
| 173 | if err != nil { |
| 174 | level.Error(logger).Log("msg", errStoringConfiguration, "err", err.Error()) |
| 175 | http.Error(w, fmt.Sprintf("%s: %s", errStoringConfiguration, err.Error()), http.StatusInternalServerError) |
| 176 | return |
| 177 | } |
| 178 | |
| 179 | w.WriteHeader(http.StatusCreated) |
| 180 | } |
| 181 | |