Skip to content
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

Open
wants to merge 6 commits into
base: master
Choose a base branch
from

Conversation

itaigilo
Copy link
Contributor

Currently, some blockstore-related stats () are constructed in a way which doesn't support more than a single blockstore type.
This extends it to allow multiple types.

This also simplifies NewMetadata params, and the code of its callers.

@itaigilo itaigilo added BI exclude-changelog PR description should not be included in next release changelog minor-change Used for PRs that don't require issue attached msb labels Mar 17, 2025
Copy link

github-actions bot commented Mar 17, 2025

E2E Test Results - DynamoDB Local - Local Block Adapter

14 passed

Copy link

github-actions bot commented Mar 17, 2025

E2E Test Results - Quickstart

11 passed

@@ -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(
Copy link
Contributor Author

@itaigilo itaigilo Mar 18, 2025

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.

MetadataManager: metadataManager,
Migrator: migrator,
Collector: collector,
CloudMetadataProvider: cloudMetadataProvider,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only removed this one. The rest is whitespaces.

@@ -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(
Copy link
Contributor Author

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, and renamed middlewareAuthenticator to authenticator (not related, but simplifies).

Copy link
Contributor

Choose a reason for hiding this comment

The 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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding this to the list of topics for the Code-Style effort -
So this will be done systematically.

@itaigilo itaigilo marked this pull request as ready for review March 18, 2025 17:20
@itaigilo itaigilo requested review from a team and nopcoder March 19, 2025 08:20
Copy link
Contributor

@guy-har guy-har left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, my main concern is inserting all the storage adapter logic into the stats library

@@ -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 {
Copy link
Contributor

@guy-har guy-har Mar 20, 2025

Choose a reason for hiding this comment

The 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.
func NewMetadata(ctx context.Context, logger logging.Logger, blockstoreType string, metadataProvider []MetadataProvider) *Metadata

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The thing is -
blockstoreType should also be an array.
So it'll be a bunch of repeated code outside of this function.

Note that BuildMetadataProvider in this file was also "aware" of blockstore logic -
It wasn't part of the NewMetadata() function, but each NewMetadata() caller was calling this function to pas its result as a param.
So I don't think that using the same trick gives much better encapsulation, only more repeated code...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not following, why should blockstore type be an array?
I know, it was done in order to not have circular dependency and not to build a factory.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@guy-har I tried what you suggested, which is basically moving buildMetadataProvider to the blockfactory, so it can be implemented for Enterprise as well.
However, as you suspected, this creates a circular dependency -
Since blockfactory is using the stats package when building the block.Adapter.
This is probably why buildMetadataProvider is in this file in first place.

We can extract the metadata builder into a separate module (in modules) that will be implement by Enterprise, and I think this can solve the circular dependencies (though it requires validation) - but I think that's a huge overkill for this.

Any other suggestions?

Comment on lines +71 to +77
func getErrorMetadata() map[string]string {
return map[string]string{
cloud.IDKey: "err",
cloud.IDTypeKey: "err",
}
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's ErrorMetadata? Is it stats we want to collect?

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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.
In this case, we'll report err to the BI (instead of nil).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was this requested?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not as a product requirement, but from a functional pov -
You can check the tests here, and see that once it's nil and not err, the BI consumer will think it's not configured, instead of this being configured but failing.

I can return nil here, but this also means we won't be able to unit-test these params.

@@ -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(
Copy link
Contributor

Choose a reason for hiding this comment

The 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.

Copy link
Contributor Author

@itaigilo itaigilo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@guy-har thanks for your review.

Addressed your comments 🙏

@@ -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 {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The thing is -
blockstoreType should also be an array.
So it'll be a bunch of repeated code outside of this function.

Note that BuildMetadataProvider in this file was also "aware" of blockstore logic -
It wasn't part of the NewMetadata() function, but each NewMetadata() caller was calling this function to pas its result as a param.
So I don't think that using the same trick gives much better encapsulation, only more repeated code...

Comment on lines +71 to +77
func getErrorMetadata() map[string]string {
return map[string]string{
cloud.IDKey: "err",
cloud.IDTypeKey: "err",
}
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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.
In this case, we'll report err to the BI (instead of nil).

@itaigilo itaigilo requested a review from guy-har March 20, 2025 10:14
Copy link
Contributor

@guy-har guy-har left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm sorry, but I wasn't convinced
We can take this offline if you prefer

@itaigilo itaigilo requested a review from guy-har March 21, 2025 06:48
Copy link
Contributor

@nopcoder nopcoder left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems we embed the cloud metadata into stats. I understand that the factory was already there (which I think we can move it out) but it looks like the author use an interface wanted to make the cloud metadata provided the same way stats metadata are provided.

The stats package should provide a abstract way to construct and invoke the metadata providers - for the setup process or the process startup while trying to keep the cloud metadata outside of the stats package.

@itaigilo
Copy link
Contributor Author

Seems we embed the cloud metadata into stats. I understand that the factory was already there (which I think we can move it out) but it looks like the author use an interface wanted to make the cloud metadata provided the same way stats metadata are provided.

The stats package should provide a abstract way to construct and invoke the metadata providers - for the setup process or the process startup while trying to keep the cloud metadata outside of the stats package.

@nopcoder can you please elaborate?

There's already an abstract way for metadata providers, which is MetadataProvider.
And it would be great if we'd have a builder (module) which the Enterprise could implement.
However, as I wrote to @guy-har 's comment, if placed in the block factory module (which is the reasonable place for it imho), it creates a circular dependency. And having a separate module seems to me like an overkill.

Which solution do you have in mind?

@nopcoder
Copy link
Contributor

Which solution do you have in mind?
@itaigilo @guy-har

Sorry, I didn't go over the comments first.
I was looking into refactoring in order to provide specific storage for the cloud metadata and found that it may not have any benefit.

Explain the real issue found in the metadata provider implementation, based on the current code (except aws which I'm not 100% sure it is the case) the code try to identify information about the cloud environment lakeFS is running on :)

Seems the assumption that the default blockstore adapter will match the cloud provider and the cloud metadata will provide more information.
So, I'm blocking this one because we need to rethink how we plan to address this one.
The option I suggest is to perform cloud discovery and consider sending the information without re-collecting on "init" (setup flow)

@itaigilo
Copy link
Contributor Author

So, I'm blocking this one because we need to rethink how we plan to address this one. The option I suggest is to perform cloud discovery and consider sending the information without re-collecting on "init" (setup flow)

@nopcoder If I get it right, you're blocking this because you think that the design of the existing code is problematic (which I agree), and that this PR adds to the problem instead of solving it (which I also agree).

However, refactoring the stats code will take a decent amount time (since there is no suggested solution yet), and will introduce risks of messing up the important BI data (considering the fact that this area is not covered by tests at all).

So if that's the case, I think we should take a different approach. Since MSB data isn't being reported at the moment, I suggest to first fix the Issue itself (using the non-optimal solution in this PR), and prioritize the refactoring using our normal process (according to the usual needs + risk + availability etc.).

All this, of course, will be void if someone can come up with a nice solution for this with as low risk as possible for the stats that are currently being sent to the BI.

@nopcoder
Copy link
Contributor

I want to add that I have a suggestion, in a untested pr format, related to the cloud bi information that will check all cloud providers.

also related to the block adapter itself I think it is a different case, not related to the cloud that we can discuss with bi.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
BI exclude-changelog PR description should not be included in next release changelog minor-change Used for PRs that don't require issue attached msb
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants