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

Smithy refactor Json protocol with Single direction EventStreaming (v4/v4a/bearer) #3212

Open
wants to merge 28 commits into
base: main
Choose a base branch
from

Conversation

sbera87
Copy link
Contributor

@sbera87 sbera87 commented Dec 9, 2024

Issue #, if available:

Description of changes:

Check all that applies:

  • Did a review by yourself.
  • Added proper tests to cover this PR. (If tests are not applicable, explain.)
  • Checked if this PR is a breaking (APIs have been changed) change.
  • Checked if this PR will not introduce cross-platform inconsistent behavior.
  • Checked if this PR would require a ReadMe/Wiki update.

Check which platforms you have built SDK on to verify the correctness of this PR.

  • Linux
  • Windows
  • Android
  • MacOS
  • IOS
  • Other Platforms

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

#include <smithy/client/AwsSmithyClient.h>
#include <smithy/identity/auth/built-in/SigV4AuthSchemeResolver.h>
#include <smithy/identity/auth/built-in/SigV4AuthScheme.h>
#include <smithy/client/serializer/JsonOutcomeSerializer.h>
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Screenshot 2024-12-08 at 9 54 28 PM

#include <aws/logs/CloudWatchLogsServiceClientModel.h>
#include <smithy/client/AwsSmithyClient.h>
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Screenshot 2024-12-09 at 9 47 36 AM

@sbera87 sbera87 changed the title Smithy refactor Json protocol with EventStreaming (v4/v4a) Smithy refactor Json protocol with EventStreaming (v4/v4a/bearer) Dec 10, 2024
@@ -330,8 +352,7 @@ def generate_single_client(service_name: str,
run_command += ["--endpoint-tests", f"{endpoints_filepath}/{model_files.endpoint_tests}"]
run_command += ["--service", service_name]
run_command += ["--outputfile", output_filename]

if service_name in SMITHY_SUPPORTED_CLIENTS:
if use_smithy:
Copy link
Contributor

Choose a reason for hiding this comment

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

why did we move this to a boolean parameter, the boolean parameter seems just to be the evaluation of the statement before? seems that we dont gain much by adding the parameter.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

So the backstory is that is global and when I pass a global to collect_available_models on main thread (append to it) and then on another thread use it the changes were not visible.
because Python's Global Interpreter Lock (GIL) ensures thread safety for certain operations, but it doesn't guarantee the immediate visibility of changes to shared mutable objects (like set) across threads.

hence instead of passing the entire set, all i actually need is the indicator service within set or not. which is a boolean

]
}

SMITHY_EXCLUSION_CLIENTS = {
Copy link
Contributor

Choose a reason for hiding this comment

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

instead of generating a deny list, is there anyway we could get this from the model itself?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

so, this deny list is basically an interim way to filter services further under a protocol. From the model, there is no simple way to say detect multi auth or streaming single/bi .
We will need to parse for every model every operation for the former and operation and its request response for the latter. Hence, to simplify this, I ran a different script outside the purview of this and added the results here.

if ("protocol" in model["metadata"] and
(model["metadata"]["protocol"] == "json" or model["metadata"]["protocol"] == "rest-json")):
if key not in SMITHY_EXCLUSION_CLIENTS:
SMITHY_SUPPORTED_CLIENTS.add(key)
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 the intention here was that the SMITHY_SUPPORTED_CLIENTS global variable was meant to be a hardcoded set of clients to use for smithy generation not for something to be updated

we should move this allow/deny list logic to a function instead of updating a global variable.

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 can use a local variable to deepcopy from it before using it. Is that ok?

@@ -688,7 +698,16 @@ protected List<SdkFileEntry> generateSmithyClientSourceFile(final List<ServiceMo

VelocityContext context = createContext(serviceModels.get(i));
context.put("CppViewHelper", CppViewHelper.class);
context.put("AuthSchemeResolver", "SigV4AuthSchemeResolver");
Optional<String> firstAuthScheme = serviceModels.get(i).getAuthSchemes().stream().filter(entry->ResolverMapping.containsKey(entry)).findFirst();
if(firstAuthScheme.isPresent())
Copy link
Contributor

Choose a reason for hiding this comment

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

seems like this is the same in both generate header and generate souice, seems like we could extract it to a private method.

for (int i = 0; i < serviceModels.size(); i++) {
if(serviceModels.get(i).isUseSmithyClient())
{
continue;
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 we could take this moment to refactor some of the legacy cruft we have here. instead of making this two loops we could make a single loop with a map statement and rework how generateSmithyClientSourceFile is called. instead of doing two iterations over the service models we could do something like

return serviceModels.stream()
  .map(model -> {
     if (model.isUseSmithyClient()) {
       return GenerateSmithyClientSourceFile(model)
     } else {
       return GenerateLegacyClientSourceFile(model);
     }
   })
   .collect(Colleectors.toList());

where the logic in this loop is factored out to GenerateLegacyClient and GenerateSmithySourceFile is refactored to accept either a list or a single file in a overloaded function

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure, let me make a commit to improve this

@sbera87 sbera87 requested a review from sbiscigl December 17, 2024 19:18
Copy link
Contributor

@sbiscigl sbiscigl left a comment

Choose a reason for hiding this comment

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

Alright i think we need to step back to the design portion of this because something went wrong in design in relation to how we handle stream signing. We cannot move forward with this until we deal with it properly. We cannot add a different API for stream signing vs regular signing. the high level ask of this task is align closer with other SDKs on how they do identity and auth and this sharply deviates from them.

I think this boils down to the question

"How do we do stream signing with SRA identity and auth"

We can work on a path forward but as a team we will likely have to have a group discussion about how we want to refactor stream signing. Will talk to you offline about this. We should take a look at how java v2 handled this because they were able to handle this without deviating from the interface.

Looking at their code for how they handle auth for event streams its not immdiately apparent how they do it but lets set up some time to talk to them about they handle it.

@@ -46,6 +46,8 @@ namespace smithy {

// signer may copy the original httpRequest or create a new one
virtual SigningFutureOutcome sign(std::shared_ptr<HttpRequest> httpRequest, const IdentityT& identity, SigningProperties properties) = 0;
// for requests with event stream
virtual bool SignEventMessage(Aws::Utils::Event::Message&, Aws::String&, const IdentityT&) const { return false; };
Copy link
Contributor

Choose a reason for hiding this comment

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

We really cant add this to the interface as defined in the SRA a singer should only be the following interface

interface Signer <IdentityT extends Identity > {  						 						 							 								 
  Result<HTTPRequest, HTTPSignerError> sign(HTTPRequest: HTTPRequest, 
    identity: IdentityT , 
    signingProperties: PropertyBag);
}

why we're doing all of this is to conform the SRA so that we are less different than other SDKs when it comes to identity and auth flow.

#include <aws/core/auth/AWSCredentials.h>
#include <aws/core/auth/AWSCredentialsProviderChain.h>

#include <smithy/identity/auth/AuthSchemeResolverBase.h>
Copy link
Contributor

Choose a reason for hiding this comment

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

no actual code changed in this file but includes did. This is more of a comment on the whole PR, but we really need to cut down on lines changed so that the PR is easier to review. Theres ideas in here that would be much easier to review if it were clearer on what actually changed and what didnt.

could you please take some time to clean up this PR and remove files and lines that are changed when nothing changed? it goes a long way to make PRs reviewable.

@@ -26,6 +26,7 @@ namespace smithy {

virtual std::shared_ptr<IdentityResolverBase<IdentityT>> identityResolver() = 0;

virtual std::shared_ptr<AwsSignerBase<IdentityT>> signer() = 0;
// The same auth scheme can have a different signer based on operation supports request with event stream
virtual std::shared_ptr<AwsSignerBase<IdentityT>> signer(bool isEventStreaming = false) = 0;
Copy link
Contributor

Choose a reason for hiding this comment

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

yeah this also doesnt conform with the SRA

interface AuthScheme <T extends Identity > {
    String schemeId();
    Option <IdentityResolver <T>> identityResolver(cf: IdentityResolverConfiguration);
    Signer<T> signer(); }
}

we really need to go back to the drawing board if what the SRA recommends doesnt work for us with stream signing, and figure out the discconect.

@sbera87 sbera87 changed the title Smithy refactor Json protocol with EventStreaming (v4/v4a/bearer) Smithy refactor Json protocol with Single direction EventStreaming (v4/v4a/bearer) Jan 5, 2025
@sbera87 sbera87 requested a review from sbiscigl January 6, 2025 18:31
Copy link
Contributor

@sbiscigl sbiscigl left a comment

Choose a reason for hiding this comment

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

some functionality comments, but this PR is really hard to review, you need to focus on cleaning it up, there are hundreds of non code-genned files changed without any content changing, that needs to be cleaned up so that we can review easier, its really hard to tell what is content change and formatting changes at this point

@@ -164,7 +167,7 @@ namespace client
false/*retryable*/);
}

SigningOutcome SignRequest(std::shared_ptr<HttpRequest> httpRequest, const AuthSchemeOption& targetAuthSchemeOption) const override
SigningOutcome SignHttpRequest(std::shared_ptr<HttpRequest> httpRequest, const AuthSchemeOption& targetAuthSchemeOption) const override
Copy link
Contributor

Choose a reason for hiding this comment

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

why are we renaming this method? doesnt make sense to update things unless we have a reason

Copy link
Contributor Author

@sbera87 sbera87 Jan 15, 2025

Choose a reason for hiding this comment

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

there is a good reason behind this which was brought up. Some clients use SignRequest as class name which when used to inherit from smithy client template causes shadowing error. The name of the function has appropriate name now since it is actually signing http request and is the minimal change to address the problem. This is tested against 375 clients with no issue for now.

Example of the the error:
KMSClient.cpp:1173:35: error: must use 'class' tag to refer to type 'SignRequest' in this scope 1173 | SignOutcome KMSClient::Sign(const SignRequest& request) const

const char* requestName,
Aws::Http::HttpMethod method,
EndpointUpdateCallback&& endpointCallback) const
ResponseT MakeRequestDeserialize(Aws::AmazonWebServiceRequest const* const request, const char* requestName,
Copy link
Contributor

Choose a reason for hiding this comment

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

why are we formatting the method signature here? lets wait until we format the entire project, here it just creates noise

@@ -60,8 +67,8 @@ namespace Aws
namespace Endpoint
{
class AWSEndpoint;
}
}
} // namespace Endpoint
Copy link
Contributor

Choose a reason for hiding this comment

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

formatting, why is this important to add it now? please reduce noise on lines changed that dont impact functionality

@@ -0,0 +1,63 @@

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 actually use the event stream signer?, if not we really should remove it from this PR.

}

virtual ~AwsSigV4aSigner() {};
protected:
Copy link
Contributor

Choose a reason for hiding this comment

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

why did we move createAwsSigningConfig? if it doesnt change we shoudlnt be moving it.

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 am not sure why github shows it like this. I re-did the changes and just added the presigner and sign helper and it still shows as if its moved

@@ -28,7 +28,6 @@ namespace Aws
class AWS_CORE_API EventEncoderStream : public Aws::IOStream
Copy link
Contributor

Choose a reason for hiding this comment

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

we arent using this file in this PR, please remove it

@@ -40,7 +42,12 @@ namespace Aws
* The signing is done via the signer member.
*/
Aws::Vector<unsigned char> EncodeAndSign(const Aws::Utils::Event::Message& msg);
private:

Copy link
Contributor

Choose a reason for hiding this comment

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

not used in this PR please remove

AwsBearerTokenIdentityResolver(const Aws::Auth::BearerTokenAuthSignerProvider &bearerTokenProvider) {
auto signer = bearerTokenProvider.GetSigner(Aws::Auth::BEARER_SIGNER);
if (signer) {
m_providerChainLegacy.emplace_back(std::dynamic_pointer_cast<Aws::Client::AWSAuthBearerSigner>(signer)->BearerTokenProvider());
Copy link
Contributor

Choose a reason for hiding this comment

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

we cant call dynamic_pointer_cast because RTTI can be disabled in the SDK. likely will have to update BearerTokenAuthSignerProvider to have a concrete method to access the bearer token provider.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You are right. This is the case where to maintain backward compatibility we use the legacy signerprovider containing many signers. Since the enum Aws::Auth::BEARER_SIGNER is mapped to the type Aws::Client::AWSAuthBearerSigner, we can just use static cast here

@sbera87 sbera87 requested a review from sbiscigl January 15, 2025 04:28
@@ -56,7 +54,7 @@ namespace smithy

Aws::String m_invocationId;
Aws::Http::HttpMethod m_method;
const Aws::AmazonWebServiceRequest* m_pRequest; // optional
const Aws::AmazonWebServiceRequest* m_pRequest{nullptr}; // optional
Copy link
Contributor Author

Choose a reason for hiding this comment

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

without this initialization it crashes in integration tests in dry run

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