Skip to content

Merge credentials reloading feature branch to mainline #3712

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

Merged
merged 16 commits into from
Feb 6, 2023

Conversation

dave-fn
Copy link
Contributor

@dave-fn dave-fn commented Jan 24, 2023

Motivation and Context

Add support for reloading credentials provided by ProfileCredentialsProvider if file changes on disk.
In addition, propagate changes to other classes with similar behavior: such as DefaultCredentialsProvider, InstanceProfileCredentialsProvider and ProfileTokenProvider.
Finally, some service classes also implemented this functionality so that configuration options might be changed on the fly.

Modifications

Multiple PRs

Testing

Added new test cases
Will run integ tests

Screenshots (if appropriate)

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)

Checklist

  • I have read the CONTRIBUTING document
  • Local run of mvn install succeeds
  • My code follows the code style of this project
  • My change requires a change to the Javadoc documentation
  • I have updated the Javadoc documentation accordingly
  • I have added tests to cover my changes
  • All new and existing tests passed
  • I have added a changelog entry. Adding a new entry must be accomplished by running the scripts/new-change script and following the instructions. Commit the new file created by the script in .changes/next-release with your changes.
  • My change is to implement 1.11 parity feature and I have updated LaunchChangelog

License

  • I confirm that this pull request can be released under the Apache 2 license

…les change (#3487)

* ProfileFile can update if disk changed, reload as new instance

* ProfileCredentialsProvider reloads credentials if profile file has changes

* Created class ProfileFileRefresher

* Created ReloadingProfileCredentialsProvider; moved new logic in ProfileFile to ProfileFileRefresher

* Fix ReloadingProfileCredentialsBehavior when missing ProfileFile Supplier or Predicate, and dealing with defaults

* Consolidated ReloadingProfileCredentialsProvider functionality into ProfileCredentialsProvider

* Fix behavior when dealing with defaults

* Created ProfileFileSupplier interface; refactored

* Misc fixes

* Created package-private ProfileFileSupplierBuilder; ProfileFileSupplier now extends Supplier; Fixed Javadoc

* Fixed unit tests for default credentials file

* Removed ProfileFileSupplier.Builder interface

* Code cleanup
* Added methods for aggregating ProfileFile objects

* Removed redundant logic, changelog entry

* Removed redundant methods

* Use compare and set to make thread safe
* Misc fixes

* Reload credentials by DefaultCredentialsProvider; pass supplier to InstanceProfileCredentialsProvider

* Fix code alignment
* Updated ProfileTokenProvider

* Updated tests, do not explicitly swallow exceptions

* ProfileTokenProviderLoader can use Supplier<Profilefile> internally

* Simplified ProfileTokenProviderLoader API; implemented synchronized block
* S3 support classes take Supplier<ProfileFile>

* Review comments
* Presigners, other Support classes take Supplier<ProfileFile>

* Split new ProfileFile tests from existing parameterized tests

* Improved tests readability
#3692)

* Leverage SdkClientOption and SdkExecutionAttributes; fallback to simple ProfileFile

* Addressed review comments
@dave-fn dave-fn requested a review from a team as a code owner January 24, 2023 21:03
Comment on lines 154 to 156
if (profileFile instanceof SdkAutoCloseable) {
((SdkAutoCloseable) profileFile).close();
}
Copy link
Contributor

Choose a reason for hiding this comment

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

This is a red flag to me: closing something we didn't necessarily create. What if this is being used by someone else and we just closed it/broke it?

My bigger question is: why are profile file suppliers closeable?

Copy link
Contributor Author

@dave-fn dave-fn Jan 26, 2023

Choose a reason for hiding this comment

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

A problem indeed. I even brought this up during a discussion, so I'm not sure why I didn't remove it.

Re: closeable suppliers--it's only because the specific implementation with reloadWhenModified uses ProfileFileRefresher internally, which in turn uses CachedSupplier being AutoCloseable.
This is also something you did touch upon in another comment.

= ProfileFileLocation.configurationFileLocation()
.map(path -> reloadWhenModified(path, ProfileFile.Type.CONFIGURATION));

ProfileFileSupplier supplier = () -> null;
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we return an empty file instead of null? Or do we handle null everywhere that we handle profile files?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Empty file indeed. Changed.

aggregator.addFile(supplier.get());
}

return refreshAndGetCurrentAggregate(aggregator);
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we really need to re-aggregate with every profile file get()?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

My understanding is that if an aggregate file is made up of N subfiles, then whenever we call get() we need to look at the new contents of the individual files. The need to reaggregate is to determine if the new contents are different from the current aggregate.

Copy link
Contributor

Choose a reason for hiding this comment

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

Got it, yeah if we can avoid re-aggregating when the files haven't changed that's a good fix.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Reimplemented previous code that was looking at whether the individual files had changes. With this new version, we should not re-aggregate if not needed.

import software.amazon.awssdk.profiles.internal.ProfileFileRefresher;

@SdkInternalApi
final class ProfileFileSupplierBuilder {
Copy link
Contributor

Choose a reason for hiding this comment

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

Does anything use this class?

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 a test class. Mainly for the clock() method making it easier to setup tests involving timing.

Copy link
Contributor

Choose a reason for hiding this comment

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

Gotcha, I searched this CR to see if things were using it and I must have missed something using it.


@Override
public void close() {
profileFileCache.close();
Copy link
Contributor

Choose a reason for hiding this comment

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

We only need to close the cached supplier when it is async. I think it's fine to exclude this close for now so that we don't have to deal with managing the lifecycle of a profile file supplier.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Removed

Comment on lines +58 to +60
this.profileFileCache = CachedSupplier.builder(this::refreshResult)
.clock(this.clock)
.build();
Copy link
Contributor

Choose a reason for hiding this comment

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

It doesn't look like we're actually using the cached supplier here for any of its caching functionality, just as a proxy for calling refreshResult. Do we actually need it, or can we rewrite this to not require it?

Copy link
Contributor Author

@dave-fn dave-fn Jan 26, 2023

Choose a reason for hiding this comment

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

Yeah. We can probably discuss this offline, but yes, the original intent of CachedSupplier was to abstract away managing individually the profile files. I may have chipped too much off and now it doesn't really make sense to use it.
One benefit of still using the cached supplier, if I understand correctly is to avoid refreshing a value when the request occurs within a timeframe (jitter time), which in this case means not hitting the disk excessively in a short amount of time.

Copy link
Contributor

Choose a reason for hiding this comment

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

Ah, I didn't think of that benefit. I think excluding jittering for local resources isn't a major risk. The failure mode is pretty different than a remote resource where jittering becomes important.

Comment on lines 106 to 107
Instant now = clock.instant();
Instant staleTime = now;
Copy link
Contributor

Choose a reason for hiding this comment

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

Why have two variables for the same value?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Was being too verbose. Remove this and other instance.

} catch (RuntimeException exception) {
Instant now = Instant.now();
Instant staleTime = now;
ProfileFile exceptionProfileFile = exceptionHandler.apply(exception);
Copy link
Contributor

Choose a reason for hiding this comment

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

Why do we not just throw the exception? What's the purpose of an exception profile file?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I was copying CachedTokenRefresher. I guess we could recover from an exception and provide a fallback profile file, maybe the default.

Copy link
Contributor

Choose a reason for hiding this comment

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

Interesting. I was thinking the intuitive behavior would just be to throw the exception (failing whatever profile file refresh is happening) and then let the next get() call try again. Essentially, push the failure handling upstream.

Trying to do something more intelligent might be confusing for the user to understand.

Copy link
Contributor Author

@dave-fn dave-fn Jan 27, 2023

Choose a reason for hiding this comment

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

Agreed this may be too complex. Removed.

@dave-fn dave-fn force-pushed the feature/master/credentials-reload branch from 60e3eae to adac974 Compare January 27, 2023 20:38
@sonarqubecloud
Copy link

sonarqubecloud bot commented Feb 6, 2023

SonarCloud Quality Gate failed.    Quality Gate failed

Bug A 0 Bugs
Vulnerability A 0 Vulnerabilities
Security Hotspot A 0 Security Hotspots
Code Smell A 295 Code Smells

77.7% 77.7% Coverage
4.4% 4.4% Duplication

@dave-fn dave-fn merged commit f3a111d into master Feb 6, 2023
@dave-fn dave-fn deleted the feature/master/credentials-reload branch February 6, 2023 19:39
aws-sdk-java-automation added a commit that referenced this pull request Mar 5, 2025
…59e84a727

Pull request: release <- staging/0065af7f-0a1b-4ce9-b143-81d59e84a727
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.

3 participants