Skip to content

Commit

Permalink
Merge pull request #8687 from kdaily/event-ordering-params-endpoints-v2
Browse files Browse the repository at this point in the history
[v2] Emit handlers before endpoint resolution
  • Loading branch information
kdaily committed May 23, 2024
2 parents 04c77cf + d1c0301 commit 96feaf7
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 5 deletions.
5 changes: 5 additions & 0 deletions .changes/next-release/bugfix-endpoints-90314.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"type": "bugfix",
"category": "endpoints",
"description": "Include params set in provide-client-param event handlers in dynamic context params for endpoint resolution."
}
9 changes: 6 additions & 3 deletions awscli/botocore/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -602,7 +602,6 @@ def _resolve_signature_version(self, service_name, resolved):


class BaseClient(object):

# This is actually reassigned with the py->op_name mapping
# when the client creator creates the subclass. This value is used
# because calls such as client.get_paginator('list_objects') use the
Expand Down Expand Up @@ -682,6 +681,12 @@ def _make_api_call(self, operation_name, api_params):
'auth_type': operation_model.auth_type,
}

api_params = self._emit_api_params(
api_params=api_params,
operation_model=operation_model,
context=request_context,
)

(
endpoint_url,
additional_headers,
Expand Down Expand Up @@ -756,8 +761,6 @@ def _convert_to_request_dict(
headers=None,
set_user_agent_header=True,
):
api_params = self._emit_api_params(
api_params, operation_model, context)
request_dict = self._serializer.serialize_to_request(
api_params, operation_model)
if not self._client_config.inject_host_prefix:
Expand Down
11 changes: 10 additions & 1 deletion awscli/botocore/signers.py
Original file line number Diff line number Diff line change
Expand Up @@ -614,6 +614,11 @@ def generate_presigned_url(self, ClientMethod, Params=None, ExpiresIn=3600,

operation_model = self.meta.service_model.operation_model(
operation_name)
params = self._emit_api_params(
api_params=params,
operation_model=operation_model,
context=context,
)
bucket_is_arn = ArnParser.is_arn(params.get('Bucket', ''))
(
endpoint_url,
Expand Down Expand Up @@ -738,7 +743,11 @@ def generate_presigned_post(self, Bucket, Key, Fields=None, Conditions=None,
# serialized to what a presign post requires.
operation_model = self.meta.service_model.operation_model(
'CreateBucket')
params = {'Bucket': bucket}
params = self._emit_api_params(
api_params={'Bucket': bucket},
operation_model=operation_model,
context=context,
)
bucket_is_arn = ArnParser.is_arn(params.get('Bucket', ''))
(
endpoint_url,
Expand Down
36 changes: 35 additions & 1 deletion tests/functional/botocore/test_context_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,7 @@ def test_client_context_param_sent_to_endpoint_resolver(
),
)

# Stub client to prevent a request from getting sent and asceertain that
# Stub client to prevent a request from getting sent and ascertain that
# only a single request would get sent. Wrap the EndpointProvider's
# resolve_endpoint method for inspecting the arguments it gets called with.
with ClientHTTPStubber(client, strict=True) as http_stubber:
Expand Down Expand Up @@ -475,3 +475,37 @@ def test_dynamic_context_param_sent_to_endpoint_resolver(
)
else:
mock_resolve_endpoint.assert_called_once_with(Region='us-east-1')

def test_dynamic_context_param_from_event_handler_sent_to_endpoint_resolver(
monkeypatch,
patched_session,
):
# patch loader to return fake service model and fake endpoint ruleset
patch_load_service_model(
patched_session,
monkeypatch,
FAKE_MODEL_WITH_DYNAMIC_CONTEXT_PARAM,
FAKE_RULESET_WITH_DYNAMIC_CONTEXT_PARAM,
)
# event handler for provide-client-params that modifies the value of the
# MockOpParam parameter
def change_param(params, **kwargs):
params['MockOpParam'] = 'mock-op-param-value-2'
client = patched_session.create_client(
'otherservice', region_name='us-east-1'
)
client.meta.events.register_last(
'provide-client-params.other-service.*', change_param
)
with ClientHTTPStubber(client, strict=True) as http_stubber:
http_stubber.add_response(status=200)
with mock.patch.object(
client._ruleset_resolver._provider,
'resolve_endpoint',
wraps=client._ruleset_resolver._provider.resolve_endpoint,
) as mock_resolve_endpoint:
client.mock_operation(MockOpParam='mock-op-param-value-1')
mock_resolve_endpoint.assert_called_once_with(
Region='us-east-1',
FooDynamicContextParamName='mock-op-param-value-2',
)
27 changes: 27 additions & 0 deletions tests/unit/botocore/test_signers.py
Original file line number Diff line number Diff line change
Expand Up @@ -868,6 +868,33 @@ def test_generate_presign_url_emits_is_presign_in_context(self):
'the following kwargs emitted: %s' % kwargs
)

def test_context_param_from_event_handler_sent_to_endpoint_resolver(self):
def change_bucket_param(params, **kwargs):
params['Bucket'] = 'mybucket-bar'
self.client.meta.events.register_last(
'provide-client-params.s3.*', change_bucket_param
)
self.client.generate_presigned_url(
'get_object', Params={'Bucket': 'mybucket-foo', 'Key': self.key}
)
ref_request_dict = {
'body': b'',
# If the bucket name set in the provide-client-params event handler
# was correctly passed to the endpoint provider as a dynamic context
# parameter, it will appear in the URL and the auth_path:
'url': 'https://mybucket-bar.s3.us-east-1.amazonaws.com/mykey',
'headers': {},
'auth_path': '/mybucket-bar/mykey',
'query_string': {},
'url_path': '/mykey',
'method': 'GET',
'context': mock.ANY,
}
self.generate_url_mock.assert_called_with(
request_dict=ref_request_dict,
expires_in=3600,
operation_name='GetObject',
)

class TestGeneratePresignedPost(unittest.TestCase):
def setUp(self):
Expand Down

0 comments on commit 96feaf7

Please sign in to comment.