mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-11-09 21:38:19 +01:00
* s3vectors: attribute request and traffic metrics to authorized buckets * s3vectors: emit resource and identity audit events * s3vectors: apply existing S3 request limits and preserve JSON errors * s3vectors: select limit resources by the dispatched operation * s3vectors: count decoded chunked request bodies against byte limits
77 lines
3.0 KiB
Go
77 lines
3.0 KiB
Go
package s3vectors
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
|
|
"github.com/gorilla/mux"
|
|
"github.com/prometheus/client_golang/prometheus/testutil"
|
|
"github.com/seaweedfs/seaweedfs/weed/s3api/s3tables"
|
|
"github.com/seaweedfs/seaweedfs/weed/s3api/s3tables/s3tablestest"
|
|
"github.com/seaweedfs/seaweedfs/weed/stats"
|
|
)
|
|
|
|
func TestVectorMetricsAttributeAuthorizedBuckets(t *testing.T) {
|
|
fs := s3tablestest.Start(t)
|
|
s := NewServer(s3tables.NewManagerClient(fs.Client), headerAuth{}, newFakeVectors(0))
|
|
var limitCalls int
|
|
s.SetLimiter(func(next http.HandlerFunc, action string) http.HandlerFunc {
|
|
return func(w http.ResponseWriter, r *http.Request) { limitCalls++; next(w, r) }
|
|
})
|
|
router := mux.NewRouter()
|
|
s.RegisterRoutes(router)
|
|
request := func(identity, operation string, payload interface{}) *httptest.ResponseRecorder {
|
|
t.Helper()
|
|
body, err := json.Marshal(payload)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
r := httptest.NewRequest(http.MethodPost, "/"+operation, bytes.NewReader(body))
|
|
r.Header.Set("X-Test-Identity", identity)
|
|
w := httptest.NewRecorder()
|
|
router.ServeHTTP(w, r)
|
|
return w
|
|
}
|
|
const bucket = "metrics-vector-bucket"
|
|
if w := request("", "CreateVectorBucket", CreateVectorBucketRequest{VectorBucketName: bucket}); w.Code != http.StatusOK {
|
|
t.Fatalf("create: %d %s", w.Code, w.Body)
|
|
}
|
|
count := stats.S3RequestCounter.WithLabelValues("s3vectors.GetVectorBucket", "200", bucket)
|
|
before := testutil.ToFloat64(count)
|
|
if w := request("", "GetVectorBucket", GetVectorBucketRequest{VectorBucketArn: s.vectorBucketArn(bucket)}); w.Code != http.StatusOK {
|
|
t.Fatalf("get by ARN: %d %s", w.Code, w.Body)
|
|
}
|
|
if got := testutil.ToFloat64(count) - before; got != 1 {
|
|
t.Fatalf("bucket requests = %v, want 1", got)
|
|
}
|
|
denied := stats.S3RequestCounter.WithLabelValues("s3vectors.GetVectorBucket", "403", "")
|
|
before = testutil.ToFloat64(denied)
|
|
if w := request("stranger", "GetVectorBucket", GetVectorBucketRequest{VectorBucketName: bucket}); w.Code != http.StatusForbidden {
|
|
t.Fatalf("unauthorized get: %d %s", w.Code, w.Body)
|
|
}
|
|
if got := testutil.ToFloat64(denied) - before; got != 1 {
|
|
t.Fatalf("unattributed denied requests = %v, want 1", got)
|
|
}
|
|
if got := testutil.ToFloat64(stats.S3BucketTrafficReceivedBytesCounter.WithLabelValues(bucket)); got <= 0 {
|
|
t.Fatalf("received bytes = %v", got)
|
|
}
|
|
if got := testutil.ToFloat64(stats.S3BucketTrafficSentBytesCounter.WithLabelValues(bucket)); got <= 0 {
|
|
t.Fatalf("sent bytes = %v", got)
|
|
}
|
|
if got := testutil.ToFloat64(stats.S3InFlightRequestsGauge.WithLabelValues("s3vectors.GetVectorBucket")); got != 0 {
|
|
t.Fatalf("in-flight requests = %v after responses", got)
|
|
}
|
|
r := httptest.NewRequest(http.MethodGet, tagsPathPrefix+s.vectorBucketArn(bucket), nil)
|
|
w := httptest.NewRecorder()
|
|
router.ServeHTTP(w, r)
|
|
if w.Code != http.StatusOK || testutil.ToFloat64(stats.S3RequestCounter.WithLabelValues("s3vectors.ListTagsForResource", "200", bucket)) == 0 {
|
|
t.Fatalf("tag metrics: %d %s", w.Code, w.Body)
|
|
}
|
|
if limitCalls != 4 {
|
|
t.Fatalf("limiter calls = %d, want 4", limitCalls)
|
|
}
|
|
}
|