Skip to content

Commit f476904

Browse files
pstibranygotjosh
andauthored
Expose deletion of AM config via /multitenant_alertmanager/delete_tenant_config (#3900)
Co-authored-by: gotjosh <[email protected]> Signed-off-by: Peter Štibraný <[email protected]>
1 parent d6d0669 commit f476904

File tree

6 files changed

+69
-0
lines changed

6 files changed

+69
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@
9191
* `cortex_bucket_store_chunk_pool_returned_bytes_total`
9292
* [ENHANCEMENT] Alertmanager: load alertmanager configurations from object storage concurrently, and only load necessary configurations, speeding configuration synchronization process and executing fewer "GET object" operations to the storage when sharding is enabled. #3898
9393
* [ENHANCEMENT] Blocks storage: Ingester can now stream entire chunks instead of individual samples to the querier. At the moment this feature must be explicitly enabled either by using `-ingester.stream-chunks-when-using-blocks` flag or `ingester_stream_chunks_when_using_blocks` (boolean) field in runtime config file, but these configuration options are temporary and will be removed when feature is stable. #3889
94+
* [ENHANCEMENT] Alertmanager: New endpoint `/multitenant_alertmanager/delete_tenant_config` to delete configuration for tenant identified by `X-Scope-OrgID` header. This is an internal endpoint, available even if Alertmanager API is not enabled by using `-experimental.alertmanager.enable-api`. #3900
9495
* [BUGFIX] Cortex: Fixed issue where fatal errors and various log messages where not logged. #3778
9596
* [BUGFIX] HA Tracker: don't track as error in the `cortex_kv_request_duration_seconds` metric a CAS operation intentionally aborted. #3745
9697
* [BUGFIX] Querier / ruler: do not log "error removing stale clients" if the ring is empty. #3761

docs/api/_index.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ For the sake of clarity, in this document we have grouped API endpoints by servi
5353
| [Alertmanager status](#alertmanager-status) | Alertmanager | `GET /multitenant_alertmanager/status` |
5454
| [Alertmanager ring status](#alertmanager-ring-status) | Alertmanager | `GET /multitenant_alertmanager/ring` |
5555
| [Alertmanager UI](#alertmanager-ui) | Alertmanager | `GET /<alertmanager-http-prefix>` |
56+
| [Alertmanager Delete Tenant Configuration](#alertmanager-delete-tenant-configuration) | Alertmanager | `POST /multitenant_alertmanager/delete_tenant_config` |
5657
| [Get Alertmanager configuration](#get-alertmanager-configuration) | Alertmanager | `GET /api/v1/alerts` |
5758
| [Set Alertmanager configuration](#set-alertmanager-configuration) | Alertmanager | `POST /api/v1/alerts` |
5859
| [Delete Alertmanager configuration](#delete-alertmanager-configuration) | Alertmanager | `DELETE /api/v1/alerts` |
@@ -683,6 +684,18 @@ Displays the Alertmanager UI.
683684

684685
_Requires [authentication](#authentication)._
685686

687+
### Alertmanager Delete Tenant Configuration
688+
689+
```
690+
POST /multitenant_alertmanager/delete_tenant_config
691+
```
692+
693+
This endpoint deletes configuration for a tenant identified by `X-Scope-OrgID` header.
694+
It is internal, available even if Alertmanager API is not enabled by using `-experimental.alertmanager.enable-api`.
695+
The endpoint returns a status code of `200` if the user's configuration has been deleted, or it didn't exist in the first place.
696+
697+
_Requires [authentication](#authentication)._
698+
686699
### Get Alertmanager configuration
687700

688701
```

pkg/alertmanager/alertstore/store.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ type AlertStore interface {
3737
SetAlertConfig(ctx context.Context, cfg alertspb.AlertConfigDesc) error
3838

3939
// DeleteAlertConfig deletes the alertmanager configuration for an user.
40+
// If configuration for the user doesn't exist, no error is reported.
4041
DeleteAlertConfig(ctx context.Context, user string) error
4142
}
4243

pkg/alertmanager/api.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,8 @@ func (am *MultitenantAlertmanager) SetUserConfig(w http.ResponseWriter, r *http.
112112
w.WriteHeader(http.StatusCreated)
113113
}
114114

115+
// DeleteUserConfig is exposed via user-visible API (if enabled, uses DELETE method), but also as an internal endpoint using POST method.
116+
// Note that if no config exists for a user, StatusOK is returned.
115117
func (am *MultitenantAlertmanager) DeleteUserConfig(w http.ResponseWriter, r *http.Request) {
116118
logger := util_log.WithContext(r.Context(), am.logger)
117119
userID, err := tenant.TenantID(r.Context())

pkg/alertmanager/api_test.go

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,18 @@ package alertmanager
22

33
import (
44
"bytes"
5+
"context"
56
"fmt"
67
"io/ioutil"
78
"net/http"
89
"net/http/httptest"
910
"testing"
1011

12+
"github.com/go-kit/kit/log"
13+
"github.com/thanos-io/thanos/pkg/objstore"
14+
15+
"github.com/cortexproject/cortex/pkg/alertmanager/alertspb"
16+
"github.com/cortexproject/cortex/pkg/alertmanager/alertstore/bucketclient"
1117
util_log "github.com/cortexproject/cortex/pkg/util/log"
1218

1319
"github.com/stretchr/testify/require"
@@ -148,3 +154,48 @@ template_files:
148154
})
149155
}
150156
}
157+
158+
func TestMultitenantAlertmanager_DeleteUserConfig(t *testing.T) {
159+
storage := objstore.NewInMemBucket()
160+
alertStore := bucketclient.NewBucketAlertStore(storage, nil, log.NewNopLogger())
161+
162+
am := &MultitenantAlertmanager{
163+
store: alertStore,
164+
logger: util_log.Logger,
165+
}
166+
167+
require.NoError(t, alertStore.SetAlertConfig(context.Background(), alertspb.AlertConfigDesc{
168+
User: "test_user",
169+
RawConfig: "config",
170+
}))
171+
172+
require.Equal(t, 1, len(storage.Objects()))
173+
174+
req := httptest.NewRequest("POST", "/multitenant_alertmanager/delete_tenant_config", nil)
175+
// Missing user returns error 401. (DeleteUserConfig does this, but in practice, authentication middleware will do it first)
176+
{
177+
rec := httptest.NewRecorder()
178+
am.DeleteUserConfig(rec, req)
179+
require.Equal(t, http.StatusUnauthorized, rec.Code)
180+
require.Equal(t, 1, len(storage.Objects()))
181+
}
182+
183+
// With user in the context.
184+
ctx := user.InjectOrgID(context.Background(), "test_user")
185+
req = req.WithContext(ctx)
186+
{
187+
rec := httptest.NewRecorder()
188+
am.DeleteUserConfig(rec, req)
189+
require.Equal(t, http.StatusOK, rec.Code)
190+
require.Equal(t, 0, len(storage.Objects()))
191+
}
192+
193+
// Repeating the request still reports 200
194+
{
195+
rec := httptest.NewRecorder()
196+
am.DeleteUserConfig(rec, req)
197+
198+
require.Equal(t, http.StatusOK, rec.Code)
199+
require.Equal(t, 0, len(storage.Objects()))
200+
}
201+
}

pkg/api/api.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ func (a *API) RegisterAlertmanager(am *alertmanager.MultitenantAlertmanager, tar
167167
// Ensure this route is registered before the prefixed AM route
168168
a.RegisterRoute("/multitenant_alertmanager/status", am.GetStatusHandler(), false, "GET")
169169
a.RegisterRoute("/multitenant_alertmanager/ring", http.HandlerFunc(am.RingHandler), false, "GET", "POST")
170+
a.RegisterRoute("/multitenant_alertmanager/delete_tenant_config", http.HandlerFunc(am.DeleteUserConfig), true, "POST")
170171

171172
// UI components lead to a large number of routes to support, utilize a path prefix instead
172173
a.RegisterRoutesWithPrefix(a.cfg.AlertmanagerHTTPPrefix, am, true)

0 commit comments

Comments
 (0)