Skip to content

Commit

Permalink
Merge pull request awsdocs#1658 from Laren-AWS/Laren-AWS/s3-presignedurl
Browse files Browse the repository at this point in the history
S3 presigned URL example with Requests package.
  • Loading branch information
Doug-AWS authored Feb 24, 2021
2 parents 22e8d84 + fc2fb5d commit ba6357c
Show file tree
Hide file tree
Showing 6 changed files with 128 additions and 74 deletions.
6 changes: 6 additions & 0 deletions python/example_code/s3/.metadata.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ files:
- path: s3_basics/object_wrapper.py
services:
- s3
- path: s3_basics/presigned_url.py
services:
- s3
- path: s3_basics/test/conftest.py
services:
- s3
Expand All @@ -22,6 +25,9 @@ files:
- path: s3_basics/test/test_object_wrapper.py
services:
- s3
- path: s3_basics/test/test_presigned_url.py
services:
- s3
...
---
# Amazon S3 file transfer demo
Expand Down
34 changes: 17 additions & 17 deletions python/example_code/s3/s3_basics/ReadMe.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ Learn to create, get, remove, and configure buckets and objects.
Credentials Reference Guide](https://docs.aws.amazon.com/credref/latest/refdocs/creds-config-files.html).
- Python 3.7 or later
- Boto 3 1.11.10 or later
- Requests 2.24.0 or later
- PyTest 5.3.5 or later (to run unit tests)

## Cautions
Expand All @@ -30,28 +31,27 @@ Learn to create, get, remove, and configure buckets and objects.

## Running the code

Both `bucket_wrapper.py` and `object_wrapper.py` contain `usage_demo` functions
that demonstrate ways to use the functions in their respective modules.
For example, to see the bucket demonstration, run the module in a command window.
**bucket_wrapper.py** and **object_wrapper.py**

These scripts contain `usage_demo` functions that demonstrate ways to use the
functions in their respective modules. For example, to see the bucket demonstration,
run the module in a command window.

```
python -m bucket_wrapper
```

You can also run individual functions in the Python shell to make requests to your
AWS account. For example, run the following commands to create a bucket, upload
an object, get the object, empty the bucket, and delete the bucket.

> python
>>> import time
>>> bucket_name = f"bucket{time.time_ns()}"
>>> import bucket_wrapper
>>> bucket = bucket_wrapper.create_bucket(bucket_name, region='us-west-2')
>>> import object_wrapper
>>> object_wrapper.put_object(bucket, 'my-test-object', b'My test data')
>>> obj = object_wrapper.get_object(bucket, 'my-test-object')
>>> object_wrapper.empty_bucket(bucket)
>>> bucket_wrapper.delete_bucket(bucket)
**presigned_url.py**

This script generates a presigned URL and uses the Requests package to get or
put a file in an Amazon S3 bucket. For example, run the following command to get
a file from Amazon S3 at a command prompt.

```
python -m presigned_url.py your-bucket-name your-object-key get
```

Run the script with the `-h` flag to get more help.

## Running the tests

Expand Down
40 changes: 0 additions & 40 deletions python/example_code/s3/s3_basics/bucket_wrapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -405,37 +405,6 @@ def generate_presigned_post(bucket_name, object_key, expires_in):
return response


def generate_presigned_url(bucket_name, client_method, method_parameters,
expires_in):
"""
Generate a presigned Amazon S3 URL that can be used to perform an action on
a bucket. A presigned URL can be used for a limited time to let someone without
an AWS account perform an action.
Usage is shown in usage_demo at the end of this module.
:param bucket_name: The name of the bucket on which the action can be performed.
:param client_method: The name of the client method that the URL performs.
:param method_parameters: The parameters of the specified client method.
:param expires_in: The number of seconds the presigned URL is valid for.
:return: The presigned URL.
"""
s3 = get_s3()
try:
url = s3.meta.client.generate_presigned_url(
ClientMethod=client_method,
Params=method_parameters,
ExpiresIn=expires_in
)
logger.info("Got presigned URL: %s", url)
except ClientError:
logger.exception("Couldn't get a presigned URL for bucket '%s' "
"and client method '%s'.",
bucket_name, client_method)
raise
return url


def usage_demo():
"""Demonstrates ways to use the functions in this module."""
prefix = 'usage-demo-bucket-wrapper-'
Expand Down Expand Up @@ -518,15 +487,6 @@ def usage_demo():
print(f"Bucket {bucket.name} has lifecycle configuration {json.dumps(get_rules)}.")
delete_lifecycle_configuration(bucket.name)

url = generate_presigned_url(
bucket.name,
'list_objects',
{'Bucket': bucket.name},
10
)
print(f"Generated a pre-signed URL that can be used to list the objects in "
f"bucket {bucket.name}. The URL is {url}.")

for bucket in created_buckets:
bucket.delete()
print(f"Deleted bucket {bucket.name}.")
Expand Down
83 changes: 83 additions & 0 deletions python/example_code/s3/s3_basics/presigned_url.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0

"""
Purpose
Shows how to use the AWS SDK for Python (Boto3) with Amazon Simple Storage Service
(Amazon S3) to generate a presigned URL that can perform an action for a limited
time with your credentials. Also shows how to use the Requests package
to make a request with the URL.
"""

import argparse
import logging
import boto3
from botocore.exceptions import ClientError
import requests

logger = logging.getLogger(__name__)


def generate_presigned_url(s3_client, client_method, method_parameters, expires_in):
"""
Generate a presigned Amazon S3 URL that can be used to perform an action.
:param s3_client: A Boto3 Amazon S3 client.
:param client_method: The name of the client method that the URL performs.
:param method_parameters: The parameters of the specified client method.
:param expires_in: The number of seconds the presigned URL is valid for.
:return: The presigned URL.
"""
try:
url = s3_client.generate_presigned_url(
ClientMethod=client_method,
Params=method_parameters,
ExpiresIn=expires_in
)
logger.info("Got presigned URL: %s", url)
except ClientError:
logger.exception(
"Couldn't get a presigned URL for client method '%s'.", client_method)
raise
return url


def usage_demo():
logging.basicConfig(level=logging.INFO, format='%(levelname)s: %(message)s')

print('-'*88)
print("Welcome to the Amazon S3 presigned URL demo.")
print('-'*88)

parser = argparse.ArgumentParser()
parser.add_argument('bucket', help="The name of the bucket.")
parser.add_argument('key', help="The key of the object.")
parser.add_argument(
'action', choices=('get', 'put'), help="The action to perform.")
args = parser.parse_args()

s3_client = boto3.client('s3')
client_action = 'get_object' if args.action == 'get' else 'put_object'
url = generate_presigned_url(
s3_client, client_action, {'Bucket': args.bucket, 'Key': args.key}, 1000)

print("Using the Requests package to send a request to the URL.")
response = None
if args.action == 'get':
response = requests.get(url)
elif args.action == 'put':
print("Putting data to the URL.")
with open(args.key, 'r') as object_file:
object_text = object_file.read()
response = requests.put(url, data=object_text)

print("Got response:")
print(f"Status: {response.status_code}")
print(response.text)

print('-'*88)


if __name__ == '__main__':
usage_demo()
17 changes: 0 additions & 17 deletions python/example_code/s3/s3_basics/test/test_bucket_wrapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -343,20 +343,3 @@ def test_generate_presigned_post(make_unique_name):
segments = urlparse(response['url'])
assert all([segments.scheme, segments.netloc, segments.path])
assert response['fields']['key'] == object_key


@pytest.mark.parametrize('client_method,method_parameters', [
('list_objects', {'Bucket': 'test-bucket'}),
('put_object', {'Bucket': 'test-bucket', 'Key': 'test-object'})
])
def test_generate_presigned_url(make_unique_name, client_method,
method_parameters):
""""Test that generating a presigned URL works as expected."""
bucket_name = make_unique_name('bucket')
expires_in = 60

url = bucket_wrapper.generate_presigned_url(
bucket_name, client_method, method_parameters, expires_in
)
segments = urlparse(url)
assert all([segments.scheme, segments.netloc, segments.path])
22 changes: 22 additions & 0 deletions python/example_code/s3/s3_basics/test/test_presigned_url.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0

"""
Unit tests for presigned_url.py functions.
"""

import boto3

import presigned_url


def test_generate_presigned_url():
s3_client = boto3.client('s3')
client_method = 'get_object'
method_params = {'Bucket': 'test-bucket', 'Key': 'test-key'}
expires = 10

got_url = presigned_url.generate_presigned_url(
s3_client, client_method, method_params, expires)
assert 'test-bucket' in got_url
assert 'test-key' in got_url

0 comments on commit ba6357c

Please sign in to comment.