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

Add ability to customize some timeouts in MongoDB database plugin #11600

Merged
merged 5 commits into from
May 17, 2021

Conversation

pcman312
Copy link
Contributor

This PR adds the ability to customize SocketTimeout, ConnectTimeout, and ServerSelectionTimeout within MongoDB connections. Vault passes these values to the MongoDB library when it makes a client connection.

This also makes some improvements around throughput. Previously, when an operation came to the plugin (creating/destroying a user, etc.), it would lock a mutex for the entirety of the operation. This resulted in the plugin forcing all requests to be single-threaded. This moves the mutex lock a bit lower in the plugin to try to limit its scope and allow multiple threads to be manipulating users at the same time. I did run a bunch of tests to try to produce races and didn't find any within the plugin code. However, I did find a race within the DB engine which I think is fixed in builtin/logical/database/path_rotate_credentials.go. The lock was being unlocked before the connection was being being closed & removed from the DBI map (b.connections). This probably wasn't a serious issue in practice as the map isn't changed in this manner very frequently.

@vercel vercel bot temporarily deployed to Preview – vault-storybook May 12, 2021 21:41 Inactive
@vercel vercel bot temporarily deployed to Preview – vault May 12, 2021 21:41 Inactive
// Take out the backend lock since we are swapping out the connection
b.Lock()
defer b.Unlock()

// Take the write lock on the instance
dbi.Lock()
defer dbi.Unlock()
Copy link
Contributor

Choose a reason for hiding this comment

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

Would it make sense to also move the dbi lock/unlock up so that it's before the lambda defer func above? We're modifying dbi there so we should have that lock held before releasing it right?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good catch! I don't think we strictly need to since the DBI instance is being removed and shouldn't be referenced by anything else at this point, but I'll move the dbi lock up just to be safe.

@@ -206,3 +262,29 @@ func (c *mongoDBConnectionProducer) getTLSAuth() (opts *options.ClientOptions, e
opts.SetTLSConfig(tlsConfig)
return opts, nil
}

func (c *mongoDBConnectionProducer) getTimeoutOpts() (opts *options.ClientOptions, err error) {
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: Getters don't have to include the get prefix on func names. I know we're not super consistent on this and it's less severe for private methods, but might be good to avoid this going forward.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Agreed that we should try to be consistent about this, however I argue that this isn't a getter. This is creating a new ClientOptions instance.

Copy link
Contributor

Choose a reason for hiding this comment

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

I think that c.timeoutOpts() or c.clientTimeoutOpts() would still make sense even so.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Updated

// Set initialized to true at this point since all fields are set,
// and the connection can be established at a later time.
m.Initialized = true

if req.VerifyConnection {
_, err := m.Connection(ctx)
client, err := m.mongoDBConnectionProducer.createClient(ctx)
Copy link
Contributor

Choose a reason for hiding this comment

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

How come we're changing this to call createClient directly instead of having it go through m.Connection to do this? It looks like m.Connection performs all of the logic captured in if req.VerifyConnection { ... }.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Initialize already has the mutex locked (at the top of the function), & it will deadlock (or panic - I don't recall which) when m.Connection() tries to lock it again.

Copy link
Contributor

Choose a reason for hiding this comment

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

I see. Do you know if we have to call _ = c.client.Disconnect(ctx) after the Ping call here? Asking based on the comment within m.Connection of wanting to re-create the session after the ping.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good question. We probably should if the Ping fails based on the comment on Disconnect itself to prevent any sort of resource leak. If it succeeds, we set it into the mongoDBConnectionProducer so it is reused the next time Connection is called.

@vercel vercel bot temporarily deployed to Preview – vault May 12, 2021 23:24 Inactive
@vercel vercel bot temporarily deployed to Preview – vault-storybook May 12, 2021 23:24 Inactive
@pcman312 pcman312 requested a review from calvn May 17, 2021 16:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants