Skip to content

Commit

Permalink
Merge pull request juju#16905 from SimonRichardson/fix-client-leaks
Browse files Browse the repository at this point in the history
juju#16905

The cross-model remote secrets client would call a remote model to access secret information. Unfortunately, the client was never closed once it had made that request. Thus it would keep the connection alive and all of its resources alive preventing the clean up. As the client is actively working, the garbage collector wouldn't be able to clean up the resource (the monitor in the apiclient prevented that) and it would steadily grow, based on more usage.

This fix is a relatively light touch, but the better approach would be to have a pool of connections to other models, keyed on the sourceUUID. We could think about implementing that in the future.

<!-- Why this change is needed and what it does. -->

## Checklist

<!-- If an item is not applicable, use `~strikethrough~`. -->

- [x] Code style: imports ordered, good names, simple structure, etc
- [x] Comments saying why design decisions were made
- [x] Go unit tests, with comments saying what you're testing

## QA steps

```sh
$ cd tests
$ ./main.sh secrets_iaas
```

## Links

<!-- Link to all relevant specification, documentation, bug, issue or JIRA card. -->

**Launchpad bug:** https://bugs.launchpad.net/juju/+bug/2052634

**Jira card:** JUJU-5422
  • Loading branch information
jujubot committed Feb 7, 2024
2 parents 582df30 + 64af051 commit 7b3f654
Show file tree
Hide file tree
Showing 3 changed files with 21 additions and 0 deletions.
14 changes: 14 additions & 0 deletions apiserver/facades/agent/secretsmanager/mocks/crossmodel.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions apiserver/facades/agent/secretsmanager/secrets.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ var (
type CrossModelSecretsClient interface {
GetRemoteSecretContentInfo(uri *coresecrets.URI, revision int, refresh, peek bool, sourceControllerUUID, appToken string, unitId int, macs macaroon.Slice) (*secrets.ContentParams, *secretsprovider.ModelBackendConfig, int, bool, error)
GetSecretAccessScope(uri *coresecrets.URI, appToken string, unitId int) (string, error)
Close() error
}

// SecretsManagerAPI is the implementation for the SecretsManager facade.
Expand Down Expand Up @@ -533,6 +534,8 @@ func (s *SecretsManagerAPI) getRemoteSecretContent(uri *coresecrets.URI, refresh
if err != nil {
return nil, nil, false, errors.Annotate(err, "creating remote secret client")
}
defer func() { _ = extClient.Close() }()

consumerApp := commonsecrets.AuthTagApp(s.authTag)
token, err := s.crossModelState.GetToken(names.NewApplicationTag(consumerApp))
if err != nil {
Expand Down
4 changes: 4 additions & 0 deletions apiserver/facades/agent/secretsmanager/secrets_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1288,6 +1288,7 @@ func (s *SecretsManagerSuite) TestGetSecretContentCrossModelExistingConsumerNoRe
mac := apitesting.MustNewMacaroon("id")

s.remoteClient = mocks.NewMockCrossModelSecretsClient(ctrl)
s.remoteClient.EXPECT().Close().Return(nil)

s.crossModelState.EXPECT().GetToken(names.NewApplicationTag("mariadb")).Return("token", nil)
s.secretsConsumer.EXPECT().GetSecretConsumer(uri, consumer).Return(&coresecrets.SecretConsumerMetadata{
Expand Down Expand Up @@ -1354,6 +1355,7 @@ func (s *SecretsManagerSuite) TestGetSecretContentCrossModelExistingConsumerNoRe
mac := apitesting.MustNewMacaroon("id")

s.remoteClient = mocks.NewMockCrossModelSecretsClient(ctrl)
s.remoteClient.EXPECT().Close().Return(nil)

s.crossModelState.EXPECT().GetToken(names.NewApplicationTag("mariadb")).Return("token", nil)
s.secretsConsumer.EXPECT().GetSecretConsumer(uri, consumer).Return(&coresecrets.SecretConsumerMetadata{
Expand Down Expand Up @@ -1425,6 +1427,7 @@ func (s *SecretsManagerSuite) TestGetSecretContentCrossModelExistingConsumerRefr
mac := apitesting.MustNewMacaroon("id")

s.remoteClient = mocks.NewMockCrossModelSecretsClient(ctrl)
s.remoteClient.EXPECT().Close().Return(nil)

s.crossModelState.EXPECT().GetToken(names.NewApplicationTag("mariadb")).Return("token", nil)
s.secretsConsumer.EXPECT().GetSecretConsumer(uri, consumer).Return(&coresecrets.SecretConsumerMetadata{
Expand Down Expand Up @@ -1496,6 +1499,7 @@ func (s *SecretsManagerSuite) TestGetSecretContentCrossModelNewConsumer(c *gc.C)
mac := apitesting.MustNewMacaroon("id")

s.remoteClient = mocks.NewMockCrossModelSecretsClient(ctrl)
s.remoteClient.EXPECT().Close().Return(nil)

s.crossModelState.EXPECT().GetToken(names.NewApplicationTag("mariadb")).Return("token", nil)
s.secretsConsumer.EXPECT().GetSecretConsumer(uri, consumer).Return(nil, errors.NotFoundf(""))
Expand Down

0 comments on commit 7b3f654

Please sign in to comment.