-
Notifications
You must be signed in to change notification settings - Fork 371
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
Build Blockstore stats from config #8814
Changes from all commits
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 |
---|---|---|
|
@@ -112,24 +112,39 @@ type Controller struct { | |
|
||
var usageCounter = stats.NewUsageCounter() | ||
|
||
func NewController(cfg config.Config, catalog *catalog.Catalog, authenticator auth.Authenticator, authService auth.Service, authenticationService authentication.Service, blockAdapter block.Adapter, metadataManager auth.MetadataManager, migrator Migrator, collector stats.Collector, cloudMetadataProvider cloud.MetadataProvider, actions actionsHandler, auditChecker AuditChecker, logger logging.Logger, sessionStore sessions.Store, pathProvider upload.PathProvider, usageReporter stats.UsageReporterOperations) *Controller { | ||
func NewController( | ||
cfg config.Config, | ||
catalog *catalog.Catalog, | ||
authenticator auth.Authenticator, | ||
authService auth.Service, | ||
authenticationService authentication.Service, | ||
blockAdapter block.Adapter, | ||
metadataManager auth.MetadataManager, | ||
migrator Migrator, | ||
collector stats.Collector, | ||
actions actionsHandler, | ||
auditChecker AuditChecker, | ||
logger logging.Logger, | ||
sessionStore sessions.Store, | ||
pathProvider upload.PathProvider, | ||
usageReporter stats.UsageReporterOperations, | ||
) *Controller { | ||
return &Controller{ | ||
Config: cfg, | ||
Catalog: catalog, | ||
Authenticator: authenticator, | ||
Auth: authService, | ||
Authentication: authenticationService, | ||
BlockAdapter: blockAdapter, | ||
MetadataManager: metadataManager, | ||
Migrator: migrator, | ||
Collector: collector, | ||
CloudMetadataProvider: cloudMetadataProvider, | ||
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. Only removed this one. The rest is whitespaces. |
||
Actions: actions, | ||
AuditChecker: auditChecker, | ||
Logger: logger, | ||
sessionStore: sessionStore, | ||
PathProvider: pathProvider, | ||
usageReporter: usageReporter, | ||
Config: cfg, | ||
Catalog: catalog, | ||
Authenticator: authenticator, | ||
Auth: authService, | ||
Authentication: authenticationService, | ||
BlockAdapter: blockAdapter, | ||
MetadataManager: metadataManager, | ||
Migrator: migrator, | ||
Collector: collector, | ||
Actions: actions, | ||
AuditChecker: auditChecker, | ||
Logger: logger, | ||
sessionStore: sessionStore, | ||
PathProvider: pathProvider, | ||
usageReporter: usageReporter, | ||
} | ||
} | ||
|
||
|
@@ -5155,26 +5170,28 @@ func (c *Controller) Setup(w http.ResponseWriter, r *http.Request, body apigen.S | |
return | ||
} | ||
|
||
if c.Config.GetBaseConfig().Auth.UIConfig.RBAC == config.AuthRBACExternal { | ||
baseConfig := c.Config.GetBaseConfig() | ||
|
||
if baseConfig.Auth.UIConfig.RBAC == config.AuthRBACExternal { | ||
// nothing to do - users are managed elsewhere | ||
writeResponse(w, r, http.StatusOK, apigen.CredentialsWithSecret{}) | ||
return | ||
} | ||
|
||
var cred *model.Credential | ||
if body.Key == nil { | ||
cred, err = setup.CreateInitialAdminUser(ctx, c.Auth, c.Config.GetBaseConfig(), c.MetadataManager, body.Username) | ||
cred, err = setup.CreateInitialAdminUser(ctx, c.Auth, baseConfig, c.MetadataManager, body.Username) | ||
} else { | ||
cred, err = setup.CreateInitialAdminUserWithKeys(ctx, c.Auth, c.Config.GetBaseConfig(), c.MetadataManager, body.Username, &body.Key.AccessKeyId, &body.Key.SecretAccessKey) | ||
cred, err = setup.CreateInitialAdminUserWithKeys(ctx, c.Auth, baseConfig, c.MetadataManager, body.Username, &body.Key.AccessKeyId, &body.Key.SecretAccessKey) | ||
} | ||
if err != nil { | ||
writeError(w, r, http.StatusInternalServerError, err) | ||
return | ||
} | ||
|
||
meta := stats.NewMetadata(ctx, c.Logger, c.BlockAdapter.BlockstoreType(), c.MetadataManager, c.CloudMetadataProvider) | ||
c.Collector.SetInstallationID(meta.InstallationID) | ||
c.Collector.CollectMetadata(meta) | ||
metadata := stats.NewMetadata(ctx, c.Logger, c.MetadataManager, baseConfig.StorageConfig()) | ||
c.Collector.SetInstallationID(metadata.InstallationID) | ||
c.Collector.CollectMetadata(metadata) | ||
c.Collector.CollectEvent(stats.Event{Class: "global", Name: "init", UserID: body.Username, Client: httputil.GetRequestLakeFSClient(r)}) | ||
|
||
response := apigen.CredentialsWithSecret{ | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -19,7 +19,6 @@ import ( | |
"github.com/treeverse/lakefs/pkg/authentication" | ||
"github.com/treeverse/lakefs/pkg/block" | ||
"github.com/treeverse/lakefs/pkg/catalog" | ||
"github.com/treeverse/lakefs/pkg/cloud" | ||
"github.com/treeverse/lakefs/pkg/config" | ||
"github.com/treeverse/lakefs/pkg/httputil" | ||
"github.com/treeverse/lakefs/pkg/logging" | ||
|
@@ -33,7 +32,24 @@ const ( | |
extensionValidationExcludeBody = "x-validation-exclude-body" | ||
) | ||
|
||
func Serve(cfg config.Config, catalog *catalog.Catalog, middlewareAuthenticator auth.Authenticator, authService auth.Service, authenticationService authentication.Service, blockAdapter block.Adapter, metadataManager auth.MetadataManager, migrator Migrator, collector stats.Collector, cloudMetadataProvider cloud.MetadataProvider, actions actionsHandler, auditChecker AuditChecker, logger logging.Logger, gatewayDomains []string, snippets []params.CodeSnippet, pathProvider upload.PathProvider, usageReporter stats.UsageReporterOperations) http.Handler { | ||
func Serve( | ||
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. It was too damn long for a single line. 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. Can you please provide the style template you are using, if we change to something like this I need to break it down manually on every refactor. 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. Adding this to the list of topics for the Code-Style effort - |
||
cfg config.Config, | ||
catalog *catalog.Catalog, | ||
authenticator auth.Authenticator, | ||
authService auth.Service, | ||
authenticationService authentication.Service, | ||
blockAdapter block.Adapter, | ||
metadataManager auth.MetadataManager, | ||
migrator Migrator, | ||
collector stats.Collector, | ||
actions actionsHandler, | ||
auditChecker AuditChecker, | ||
logger logging.Logger, | ||
gatewayDomains []string, | ||
snippets []params.CodeSnippet, | ||
pathProvider upload.PathProvider, | ||
usageReporter stats.UsageReporterOperations, | ||
) http.Handler { | ||
logger.Info("initialize OpenAPI server") | ||
swagger, err := apigen.GetSwagger() | ||
if err != nil { | ||
|
@@ -53,10 +69,10 @@ func Serve(cfg config.Config, catalog *catalog.Catalog, middlewareAuthenticator | |
cfg.GetBaseConfig().Logging.AuditLogLevel, | ||
cfg.GetBaseConfig().Logging.TraceRequestHeaders, | ||
cfg.GetBaseConfig().IsAdvancedAuth()), | ||
AuthMiddleware(logger, swagger, middlewareAuthenticator, authService, sessionStore, &oidcConfig, &cookieAuthConfig), | ||
AuthMiddleware(logger, swagger, authenticator, authService, sessionStore, &oidcConfig, &cookieAuthConfig), | ||
MetricsMiddleware(swagger), | ||
) | ||
controller := NewController(cfg, catalog, middlewareAuthenticator, authService, authenticationService, blockAdapter, metadataManager, migrator, collector, cloudMetadataProvider, actions, auditChecker, logger, sessionStore, pathProvider, usageReporter) | ||
controller := NewController(cfg, catalog, authenticator, authService, authenticationService, blockAdapter, metadataManager, migrator, collector, actions, auditChecker, logger, sessionStore, pathProvider, usageReporter) | ||
apigen.HandlerFromMuxWithBaseURL(controller, apiRouter, apiutil.BaseURL) | ||
|
||
r.Mount("/_health", httputil.ServeHealth()) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -27,7 +27,7 @@ type MetadataProvider interface { | |
GetMetadata(context.Context) (map[string]string, error) | ||
} | ||
|
||
func NewMetadata(ctx context.Context, logger logging.Logger, blockstoreType string, metadataProvider MetadataProvider, cloudMetadataProvider cloud.MetadataProvider) *Metadata { | ||
func NewMetadata(ctx context.Context, logger logging.Logger, metadataProvider MetadataProvider, storageConfig config.StorageConfig) *Metadata { | ||
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. The internals of the provider should stay externally, I would expect all this code to be in a storageAdapterMetadata provider. Maybe even provided by the block adapter factory. If we're already here I would suggest replacing the current signature of this function. 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. The thing is - Note that 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. I'm not following, why should blockstore type be an array? 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. @guy-har I tried what you suggested, which is basically moving We can extract the metadata builder into a separate module (in Any other suggestions? |
||
res := &Metadata{} | ||
authMetadata, err := metadataProvider.GetMetadata(ctx) | ||
if err != nil { | ||
|
@@ -39,28 +39,57 @@ func NewMetadata(ctx context.Context, logger logging.Logger, blockstoreType stri | |
} | ||
res.Entries = append(res.Entries, MetadataEntry{Name: k, Value: v}) | ||
} | ||
if cloudMetadataProvider != nil { | ||
cloudMetadata := cloudMetadataProvider.GetMetadata() | ||
for k, v := range cloudMetadata { | ||
res.Entries = append(res.Entries, MetadataEntry{Name: k, Value: v}) | ||
|
||
for _, id := range storageConfig.GetStorageIDs() { | ||
if adapterCfg := storageConfig.GetStorageByID(id); adapterCfg != nil { | ||
appendOrUpdateEntry(res, BlockstoreTypeKey, adapterCfg.BlockstoreType()) | ||
|
||
provider := buildMetadataProvider(logger, adapterCfg) | ||
cloudMetadata := provider.GetMetadata() | ||
if cloudMetadata == nil { | ||
cloudMetadata = getErrorMetadata() | ||
} | ||
for k, v := range cloudMetadata { | ||
appendOrUpdateEntry(res, k, v) | ||
} | ||
} | ||
} | ||
res.Entries = append(res.Entries, MetadataEntry{Name: BlockstoreTypeKey, Value: blockstoreType}) | ||
|
||
return res | ||
} | ||
|
||
func appendOrUpdateEntry(metadata *Metadata, key, value string) { | ||
for i, entry := range metadata.Entries { | ||
if entry.Name == key { | ||
metadata.Entries[i].Value = entry.Value + "," + value | ||
return | ||
} | ||
} | ||
metadata.Entries = append(metadata.Entries, MetadataEntry{Name: key, Value: value}) | ||
} | ||
|
||
func getErrorMetadata() map[string]string { | ||
return map[string]string{ | ||
cloud.IDKey: "err", | ||
cloud.IDTypeKey: "err", | ||
} | ||
} | ||
|
||
Comment on lines
+71
to
+77
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. What's ErrorMetadata? Is it stats we want to collect? 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. In some cases we know the blockstore type, but failing to get the metadata from the cloud-provider. 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. Was this requested? 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. Not as a product requirement, but from a functional pov - I can return |
||
type noopMetadataProvider struct{} | ||
|
||
func (n *noopMetadataProvider) GetMetadata() map[string]string { | ||
return nil | ||
return map[string]string{ | ||
cloud.IDKey: "nil", | ||
cloud.IDTypeKey: "nil", | ||
} | ||
} | ||
|
||
func BuildMetadataProvider(logger logging.Logger, c *config.BaseConfig) cloud.MetadataProvider { | ||
switch c.Blockstore.Type { | ||
func buildMetadataProvider(logger logging.Logger, c config.AdapterConfig) cloud.MetadataProvider { | ||
switch c.BlockstoreType() { | ||
case block.BlockstoreTypeGS: | ||
return gcp.NewMetadataProvider(logger) | ||
case block.BlockstoreTypeS3: | ||
s3Params, err := c.Blockstore.BlockstoreS3Params() | ||
s3Params, err := c.BlockstoreS3Params() | ||
if err != nil { | ||
logger.WithError(err).Warn("Failed to create S3 client for MetadataProvider") | ||
return &noopMetadataProvider{} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
package stats_test | ||
|
||
import ( | ||
"context" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/require" | ||
"github.com/treeverse/lakefs/pkg/cloud" | ||
"github.com/treeverse/lakefs/pkg/config" | ||
"github.com/treeverse/lakefs/pkg/logging" | ||
"github.com/treeverse/lakefs/pkg/stats" | ||
) | ||
|
||
type mockMetadataProvider struct { | ||
metadata map[string]string | ||
err error | ||
} | ||
|
||
func (m *mockMetadataProvider) GetMetadata(ctx context.Context) (map[string]string, error) { | ||
return m.metadata, m.err | ||
} | ||
|
||
const ( | ||
installationIDKey = "installation_id" | ||
installationIDValue = "test_installation_id" | ||
testEntryKey = "test_key" | ||
testEntryValue = "test_value" | ||
) | ||
|
||
func TestNewMetadata(t *testing.T) { | ||
tests := []struct { | ||
name string | ||
blockstore config.Blockstore | ||
expectedBlockstoreType string | ||
expectedIDKeyType string | ||
expectedIDKey string | ||
}{ | ||
{ | ||
name: "s3", | ||
blockstore: config.Blockstore{ | ||
Type: "s3", | ||
S3: &config.BlockstoreS3{}, | ||
}, | ||
expectedBlockstoreType: "s3", | ||
expectedIDKeyType: "err", // no s3 cloud provider in the test env, hence err | ||
expectedIDKey: "err", // no s3 cloud provider in the test env, hence err | ||
}, | ||
{ | ||
name: "gs", | ||
blockstore: config.Blockstore{ | ||
Type: "gs", | ||
GS: &config.BlockstoreGS{}, | ||
}, | ||
expectedBlockstoreType: "gs", | ||
expectedIDKeyType: "err", // no gs cloud provider in the test env, hence err | ||
expectedIDKey: "err", // no gs cloud provider in the test env, hence err | ||
}, | ||
{ | ||
name: "local", | ||
blockstore: config.Blockstore{ | ||
Type: "local", | ||
}, | ||
expectedBlockstoreType: "local", | ||
expectedIDKeyType: "nil", | ||
expectedIDKey: "nil", | ||
}, | ||
} | ||
|
||
for _, tt := range tests { | ||
ctx := context.Background() | ||
logger := logging.FromContext(ctx) | ||
provider := &mockMetadataProvider{ | ||
metadata: map[string]string{ | ||
installationIDKey: installationIDValue, | ||
testEntryKey: testEntryValue, | ||
}, | ||
} | ||
|
||
t.Run(tt.name, func(t *testing.T) { | ||
cfg := &config.BaseConfig{ | ||
Blockstore: tt.blockstore, | ||
} | ||
|
||
metadata := stats.NewMetadata(ctx, logger, provider, cfg.StorageConfig()) | ||
|
||
require.Equal(t, installationIDValue, metadata.InstallationID) | ||
require.Len(t, metadata.Entries, 5) | ||
require.Contains(t, metadata.Entries, stats.MetadataEntry{Name: installationIDKey, Value: installationIDValue}) | ||
require.Contains(t, metadata.Entries, stats.MetadataEntry{Name: testEntryKey, Value: testEntryValue}) | ||
require.Contains(t, metadata.Entries, stats.MetadataEntry{Name: stats.BlockstoreTypeKey, Value: tt.expectedBlockstoreType}) | ||
require.Contains(t, metadata.Entries, stats.MetadataEntry{Name: cloud.IDTypeKey, Value: tt.expectedIDKeyType}) | ||
require.Contains(t, metadata.Entries, stats.MetadataEntry{Name: cloud.IDKey, Value: tt.expectedIDKey}) | ||
}) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It was too damn long for a single line.
Removed
cloudMetadataProvider
.