[#321] Use correct owner id in billing metrics

Signed-off-by: Marina Biryukova <m.biryukova@yadro.com>
This commit is contained in:
Marina Biryukova 2024-02-26 17:01:13 +03:00
parent 94980059b7
commit 486b8a4284
5 changed files with 57 additions and 19 deletions

View file

@ -6,6 +6,7 @@ import (
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/auth" "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/auth"
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors" "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/logs" "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/logs"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer"
"go.uber.org/zap" "go.uber.org/zap"
) )
@ -13,6 +14,8 @@ func Auth(center auth.Center, log *zap.Logger) Func {
return func(h http.Handler) http.Handler { return func(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context() ctx := r.Context()
reqInfo := GetReqInfo(ctx)
reqInfo.User = "anon"
box, err := center.Authenticate(r) box, err := center.Authenticate(r)
if err != nil { if err != nil {
if err == auth.ErrNoAuthorizationHeader { if err == auth.ErrNoAuthorizationHeader {
@ -31,6 +34,10 @@ func Auth(center auth.Center, log *zap.Logger) Func {
ctx = SetClientTime(ctx, box.ClientTime) ctx = SetClientTime(ctx, box.ClientTime)
} }
ctx = SetAuthHeaders(ctx, box.AuthHeaders) ctx = SetAuthHeaders(ctx, box.AuthHeaders)
if box.AccessBox.Gate.BearerToken != nil {
reqInfo.User = bearer.ResolveIssuer(*box.AccessBox.Gate.BearerToken).String()
}
} }
h.ServeHTTP(w, r.WithContext(ctx)) h.ServeHTTP(w, r.WithContext(ctx))

View file

@ -12,7 +12,6 @@ import (
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data" "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data"
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/logs" "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/logs"
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/metrics" "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/metrics"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer"
"go.uber.org/zap" "go.uber.org/zap"
) )
@ -80,9 +79,8 @@ func stats(f http.HandlerFunc, resolveCID cidResolveFunc, appMetrics *metrics.Ap
// simply for the fact that it is not human-readable. // simply for the fact that it is not human-readable.
durationSecs := time.Since(statsWriter.startTime).Seconds() durationSecs := time.Since(statsWriter.startTime).Seconds()
user := resolveUser(r.Context())
cnrID := resolveCID(r.Context(), reqInfo) cnrID := resolveCID(r.Context(), reqInfo)
appMetrics.Update(user, reqInfo.BucketName, cnrID, requestTypeFromAPI(reqInfo.API), in.countBytes, out.countBytes) appMetrics.Update(reqInfo.User, reqInfo.BucketName, cnrID, requestTypeFromAPI(reqInfo.API), in.countBytes, out.countBytes)
code := statsWriter.statusCode code := statsWriter.statusCode
// A successful request has a 2xx response code // A successful request has a 2xx response code
@ -148,14 +146,6 @@ func resolveCID(log *zap.Logger, resolveBucket BucketResolveFunc) cidResolveFunc
} }
} }
func resolveUser(ctx context.Context) string {
user := "anon"
if bd, err := GetBoxData(ctx); err == nil && bd.Gate.BearerToken != nil {
user = bearer.ResolveIssuer(*bd.Gate.BearerToken).String()
}
return user
}
// WriteHeader -- writes http status code. // WriteHeader -- writes http status code.
func (w *responseWrapper) WriteHeader(code int) { func (w *responseWrapper) WriteHeader(code int) {
w.Do(func() { w.Do(func() {

View file

@ -36,6 +36,7 @@ type (
BucketName string // Bucket name BucketName string // Bucket name
ObjectName string // Object name ObjectName string // Object name
TraceID string // Trace ID TraceID string // Trace ID
User string // User owner id
URL *url.URL // Request url URL *url.URL // Request url
tags []KeyVal // Any additional info not accommodated by above fields tags []KeyVal // Any additional info not accommodated by above fields
} }

View file

@ -9,14 +9,34 @@ import (
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/auth" "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/auth"
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data" "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data"
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/middleware" "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/middleware"
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/creds/accessbox"
bearertest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer/test"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
type anonCenterMock struct {
}
func (c *anonCenterMock) Authenticate(*http.Request) (*auth.Box, error) {
return &auth.Box{
AccessBox: &accessbox.Box{
Gate: &accessbox.GateData{},
},
}, nil
}
type centerMock struct { type centerMock struct {
} }
func (c *centerMock) Authenticate(*http.Request) (*auth.Box, error) { func (c *centerMock) Authenticate(*http.Request) (*auth.Box, error) {
return &auth.Box{}, nil token := bearertest.Token()
return &auth.Box{
AccessBox: &accessbox.Box{
Gate: &accessbox.GateData{
BearerToken: &token,
},
},
}, nil
} }
type handlerMock struct { type handlerMock struct {

View file

@ -10,6 +10,7 @@ import (
"testing" "testing"
"time" "time"
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/auth"
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/metrics" "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/metrics"
"github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware" "github.com/go-chi/chi/v5/middleware"
@ -18,7 +19,7 @@ import (
) )
func TestRouterUploadPart(t *testing.T) { func TestRouterUploadPart(t *testing.T) {
chiRouter := prepareRouter(t) chiRouter := prepareRouter(t, &anonCenterMock{})
w := httptest.NewRecorder() w := httptest.NewRecorder()
r := httptest.NewRequest(http.MethodPut, "/dkirillov/fix-object", nil) r := httptest.NewRequest(http.MethodPut, "/dkirillov/fix-object", nil)
@ -33,7 +34,7 @@ func TestRouterUploadPart(t *testing.T) {
} }
func TestRouterListMultipartUploads(t *testing.T) { func TestRouterListMultipartUploads(t *testing.T) {
chiRouter := prepareRouter(t) chiRouter := prepareRouter(t, &anonCenterMock{})
w := httptest.NewRecorder() w := httptest.NewRecorder()
r := httptest.NewRequest(http.MethodGet, "/test-bucket", nil) r := httptest.NewRequest(http.MethodGet, "/test-bucket", nil)
@ -47,7 +48,7 @@ func TestRouterListMultipartUploads(t *testing.T) {
} }
func TestRouterObjectWithSlashes(t *testing.T) { func TestRouterObjectWithSlashes(t *testing.T) {
chiRouter := prepareRouter(t) chiRouter := prepareRouter(t, &anonCenterMock{})
bktName, objName := "dkirillov", "/fix/object" bktName, objName := "dkirillov", "/fix/object"
target := fmt.Sprintf("/%s/%s", bktName, objName) target := fmt.Sprintf("/%s/%s", bktName, objName)
@ -62,7 +63,7 @@ func TestRouterObjectWithSlashes(t *testing.T) {
} }
func TestRouterObjectEscaping(t *testing.T) { func TestRouterObjectEscaping(t *testing.T) {
chiRouter := prepareRouter(t) chiRouter := prepareRouter(t, &anonCenterMock{})
bktName := "dkirillov" bktName := "dkirillov"
@ -106,19 +107,38 @@ func TestRouterObjectEscaping(t *testing.T) {
} }
} }
func prepareRouter(t *testing.T) *chi.Mux { func TestOwnerIDRetrieving(t *testing.T) {
anonRouter := prepareRouter(t, &anonCenterMock{})
w := httptest.NewRecorder()
r := httptest.NewRequest(http.MethodGet, "/test-bucket", nil)
anonRouter.ServeHTTP(w, r)
resp := readResponse(t, w)
require.Equal(t, "anon", resp.ReqInfo.User)
chiRouter := prepareRouter(t, &centerMock{})
w = httptest.NewRecorder()
r = httptest.NewRequest(http.MethodGet, "/test-bucket", nil)
chiRouter.ServeHTTP(w, r)
resp = readResponse(t, w)
require.NotEqual(t, "anon", resp.ReqInfo.User)
}
func prepareRouter(t *testing.T, center auth.Center) *chi.Mux {
throttleOps := middleware.ThrottleOpts{ throttleOps := middleware.ThrottleOpts{
Limit: 10, Limit: 10,
BacklogTimeout: 30 * time.Second, BacklogTimeout: 30 * time.Second,
} }
handleMock := &handlerMock{t: t} handleMock := &handlerMock{t: t}
cntrMock := &centerMock{}
log := zaptest.NewLogger(t) log := zaptest.NewLogger(t)
metric := &metrics.AppMetrics{} metric := &metrics.AppMetrics{}
chiRouter := chi.NewRouter() chiRouter := chi.NewRouter()
AttachChi(chiRouter, nil, throttleOps, handleMock, cntrMock, log, metric) AttachChi(chiRouter, nil, throttleOps, handleMock, center, log, metric)
return chiRouter return chiRouter
} }