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

moto 1.3.14 breaks boto3 access (again) #3140

Closed
snimark opened this issue Jul 16, 2020 · 3 comments
Closed

moto 1.3.14 breaks boto3 access (again) #3140

snimark opened this issue Jul 16, 2020 · 3 comments

Comments

@snimark
Copy link

snimark commented Jul 16, 2020

I believe this might be a reemergence of a past bug (#2172).

The following code has two duplicate functions, but the second has a mock_ec2 decorator. Expected behavior would be establishing a mock ec2 client object only when using the function with the decorator, but the behavior is that it also impacts the session object (which is intended to use an instance profile).

The instance id used in both is an existing instance in my account at the time of the call. The mocked environment making the call to the EC2 instance should fail. It should be the only thing that fails.

#!/usr/bin/env python3

import boto3
from moto import mock_ec2
from pprint import pprint

def first_try():
    session = boto3.session.Session(region_name='us-east-1')
    pprint(f"first session = {session}")

    sts_client = session.client('sts')
    pprint(f"first caller identity = {sts_client.get_caller_identity()}")

    ec2_resource = session.resource('ec2')
    pprint(f"first image = {ec2_resource.images.filter(ImageIds=['ami-0591128407d57f32c'])}")

@mock_ec2
def second_try():
    session = boto3.session.Session(region_name='us-east-1')
    pprint(f"second session = {session}")

    sts_client = session.client('sts')
    pprint(f"second caller identity = {sts_client.get_caller_identity()}")

    ec2_resource = session.resource('ec2')
    pprint(f"second image = {ec2_resource.images.filter(ImageIds=['ami-0591128407d57f32c'])}")


if __name__ == "__main__":
    first_try()
    print('-' * 10)
    second_try()
$ ./example_code.py 
"first session = Session(region_name='us-east-1')"
("first caller identity = {'UserId': 'XXXXXXXXXXXXXXXXXXXXX', 'Account': "
 "'XXXXXXXXXXXX', 'Arn': 'arn:aws:iam::XXXXXXXXXXXX:user/me', "
 "'ResponseMetadata': {'RequestId': 'e435dabd-9abe-40e5-8a7c-0fe2928142be', "
 "'HTTPStatusCode': 200, 'HTTPHeaders': {'x-amzn-requestid': "
 "'e435dabd-9abe-40e5-8a7c-0fe2928142be', 'content-type': 'text/xml', "
 "'content-length': '406', 'date': 'Thu, 16 Jul 2020 14:11:49 GMT'}, "
 "'RetryAttempts': 0}}")
'first image = ec2.imagesCollection(ec2.ServiceResource(), ec2.Image)'
----------
"second session = Session(region_name='us-east-1')"
Traceback (most recent call last):
  File "./example_code.py", line 32, in <module>
    second_try()
  File "/usr/local/lib/python3.8/site-packages/moto/core/models.py", line 88, in wrapper
    result = func(*args, **kwargs)
  File "./example_code.py", line 23, in second_try
    pprint(f"second caller identity = {sts_client.get_caller_identity()}")
  File "/usr/local/lib/python3.8/site-packages/botocore/client.py", line 316, in _api_call
    return self._make_api_call(operation_name, kwargs)
  File "/usr/local/lib/python3.8/site-packages/botocore/client.py", line 635, in _make_api_call
    raise error_class(parsed_response, operation_name)
botocore.exceptions.ClientError: An error occurred (InvalidClientTokenId) when calling the GetCallerIdentity operation: The security token included in the request is invalid.

Installed via pip3:

moto==1.3.14
boto3==1.14.13
botocore==1.17.13

Using the Python mocks (not server).

Is this expected behavior? Should the explicit use of a mock for a specific resource impact outside that resource scope?

@bblommers
Copy link
Collaborator

bblommers commented Jul 19, 2020

Hi @snimark, that is the expected behaviour, yes. Botocore does not support credential mocking on a client/service basis, so they can only be mocked on a system level. So the moment you use any of the decorators, all boto-calls will use mocked credentials.

There is a workaround to un-mock the credentials, as described here: #3111.

Another workaround would be to manually start/stop mocking specific services:

def test_stuff():
  # do things with AWS sqs
  mock = mock_ec2()
  mock.start()
  # do things with mocked ec2
  mock.stop()
  # do other things against AWS sqs

Hopefully that's helpful for your usecase?

@snimark
Copy link
Author

snimark commented Jul 21, 2020

Thanks for the reply. I will see about implementing this model of cherry picking the resources to mock in our tests.

@bblommers
Copy link
Collaborator

Going to close this issue - please let us know if there are an other questions/issues though!

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

No branches or pull requests

2 participants