-
Notifications
You must be signed in to change notification settings - Fork 55
fix: credentials provider ownership #498
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
Conversation
|
A new generated diff is ready to view: __generated-main...__generated-fix-provider-ownership |
|
A new generated diff is ready to view: __generated-main...__generated-fix-provider-ownership |
ianbotsf
left a comment
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.
I like the general direction of this, it's nice and clean!
| * Wraps another [CredentialsProvider] with a no-op close implementation. This inserts a level of indirection for | ||
| * use cases when a provider is explicitly given to the SDK, and it's ownership should remain with the caller. | ||
| * This allows the SDK to treat resources as owned and not have to track ownership state. |
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.
Nit: it's → its
| // provide default no-op close | ||
| override fun close() { } | ||
|
|
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.
Comment: This seems dangerous. Given the implications of forgetting to close something, it seems like there should be no default close and implementors should have to make explicit decisions about closing.
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.
We could do that but every generated Config implements AwsClientConfig and so we would have to generate a close() method there.
We could do that and just do config.close() instead in the generated client close implementation?
It would be nice to express a way to say that a property represents a closeable resource I guess and have the config generator automatically render it in the close implementation.
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 would be nice to express a way to say that a property represents a closeable resource I guess and have the config generator automatically render it in the close implementation.
+1. Seems like going this way we'd be able to verify that a given codegen output cleans up resources as expected in CI
| override fun renderClose(writer: KotlinWriter) { | ||
| writer.addImport(RuntimeTypes.IO.Closeable) | ||
| writer.write("") | ||
| .openBlock("override fun close() {") | ||
| .write("client.close()") | ||
| .write("(config.credentialsProvider as? #T)?.close()", RuntimeTypes.IO.Closeable) | ||
| .closeBlock("}") | ||
| .write("") | ||
| } |
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.
Comment: Would be nice to have a new test for this.
| // provide default no-op close | ||
| override fun close() { } | ||
|
|
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 would be nice to express a way to say that a property represents a closeable resource I guess and have the config generator automatically render it in the close implementation.
+1. Seems like going this way we'd be able to verify that a given codegen output cleans up resources as expected in CI
|
A new generated diff is ready to view: __generated-main...__generated-fix-provider-ownership |
|
A new generated diff is ready to view: __generated-main...__generated-fix-provider-ownership |
|
Kudos, SonarCloud Quality Gate passed!
|
|
A new generated diff is ready to view: __generated-main...__generated-fix-provider-ownership |
kggilmer
left a comment
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.
Question regarding Closable and CredentialsProvider but nothing to warrant blocking the PR
| writer.write("") | ||
| .openBlock("override fun close() {") | ||
| .write("client.close()") | ||
| .write("(config.credentialsProvider as? #T)?.close()", RuntimeTypes.IO.Closeable) |
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.
question
I'm missing something regarding Closable and CredentialsProvider types. The latter doesn't specify a close method, but the WrappedCredentialsProvider does combine the two, and looks here that we check to see if the cp implements closable and then call it if so. Given this would it not be simpler to have CP simply implement Closable? Put another way, what value are we gaining by having only BorrowedCredentialsProvider implement Closable?
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.
what value are we gaining by having only
BorrowedCredentialsProviderimplementClosable
It isn't the only one that implements Closeable. All of the following do:
DefaultChainCredentialsProviderEcsCredentialsProviderImdsCredentialsProviderProfileCredentialsProvider
Environment, StsWebIdentity, StsAssumeRole, and SSO providers do not implement Closeable.
The issue is that the type is just CredentialsProvider both here and in BorrowedCredentialsProvider so both have to check if the underlying implementation actually needs to be closed or not. I have gone back and forth on this and considered making CredentialsProvider implement Closeable but ultimately decided against it to be more clear about what types do and don't need to be closed when used directly by a customer. I could be persuaded the other way though if you want to make a case for it.
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.
Personally I'm not sure what's best either way, but it may be more satisfying of "We ensure accessing AWS services is performant, secure, and reliable for developers" if CredentialProvider implements Closable. I reckon this may be so because if closability varies, intuitively it seems likely that someone may forget that a particular CP needs to be closed. Or perhaps a function that takes a non closing CP is passed a requires-closing CP during a refactor but the nuance is dropped in the refactor. If all CPs must be closed (with some of them being NOP), it seems to be less likely that this kind of bug would occur. This comes at the expense of greater overall complexity of the CP type, however the value may outweigh the cost. @ianbotsf any thoughts on this?
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.
I'm in favor of explicitly modelling closability. If it can/must be closed, it should be Closeable. Otherwise, I don't think we should unnecessarily attach closing semantics to the CredentialProvider interface because some of the implementations are closeable.
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.
Ya I can see both sides here and I hear the concern. I'm going to leave it as is for now and lets see how it shakes out.
…ible (#469) Refactor credential providers to remove CRT dependency and make them KMP compatible. Added SSO provider to default chain. Lots of misc cleanup and improvements. * feat(rt): standalone sso credentials provider (#462) * refactor(rt)!: generated sts and sts web identity credential providers (#470) * refactor(rt)!: implement kmp ecs provider (#475) * feat(rt)!: implement kmp profile credentials provider (#478) * feat(rt)!: kmp default credentials provider chain (#491) * fix: work around machine-specific Gradle bug with aws-config variants (#496) * fix: credentials provider ownership (#498) Co-authored-by: Ian Botsford <83236726+ianbotsf@users.noreply.github.com>








Issue #
N/A
Description of changes
borrow()extension that wraps an existing provider with a no-op close implementationcredentialsProviderin the service client's close implementation (if it was borrowed it will do nothing, otherwise it will close it)ImplementCloseablefor sharedAwsClientConfigAwsClientConfigand associated constructorcredentialsProviderrequired forPresignConfig(otherwise it needs to beCloseablebecause it was instantiating a default chain provider)Client.fromEnvironment()and update it's signature to useClient.Config.Builderinstead ofAwsClientLoadOptionsprofileNamethroughDefaultCredentialProviderChainconstructor. Make constructor withhttpClientEngineoverride public.By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.