Skip to content

Commit

Permalink
Merge pull request #15 from LeadingEDJE/task/12-upload-file
Browse files Browse the repository at this point in the history
#12 - Add upload utility method
  • Loading branch information
andrewdmay committed Jul 5, 2020
2 parents 06c99de + 24d59ee commit 2e6f9e1
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 3 deletions.
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ Stackmanager has the following commands:
* `deploy` - Create or update a CloudFormation stack for a specific environment/region using a ChangeSet. By default exits after creating the changeset, but can `--auto-apply`.
* `apply` - Apply a previously created ChangeSet
* `delete` - Delete an existing CloudFormation stack
* `upload` - Uploads a local file to S3. Utility method to prevent the need to use the AWS CLI or other tools.

### deploy

Expand Down Expand Up @@ -160,6 +161,25 @@ Options:
--help Show this message and exit.
```
### Upload
```
Usage: stackmanager upload [OPTIONS]

Uploads a File to S3. This might be a large CloudFormation template, or a
Lambda zip file

Options:
-p, --profile TEXT AWS Profile, will use default or environment variables
if not specified

-r, --region TEXT AWS Region to upload to [required]
-f, --filename TEXT File to upload [required]
-b, --bucket TEXT Bucket to upload to [required]
-k, --key TEXT Key to upload to [required]
--help Show this message and exit.
```
## CI/CD Pipeline support
### Azure DevOps
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

setup(
name='stackmanager',
version='0.4',
version='0.5',
description='Utility to manage CloudFormation stacks using YAML configuration file',
long_description=README,
long_description_content_type='text/markdown',
Expand Down
25 changes: 23 additions & 2 deletions stackmanager/cli.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
#!/usr/bin/env python
import click
from stackmanager.exceptions import StackError, ValidationError
from stackmanager.exceptions import StackError, TransferError, ValidationError
from stackmanager.loader import load_config
from stackmanager.messages import error
from stackmanager.runner import create_runner
from stackmanager.uploader import create_uploader


@click.group(chain=True)
Expand Down Expand Up @@ -78,5 +79,25 @@ def delete(ctx, profile, config, environment, region, retain_resources):
exit(1)


@cli.command()
@click.pass_context
@click.option('-p', '--profile', help='AWS Profile, will use default or environment variables if not specified')
@click.option('-r', '--region', required=True, help='AWS Region to upload to')
@click.option('-f', '--filename', required=True, help='File to upload')
@click.option('-b', '--bucket', required=True, help='Bucket to upload to')
@click.option('-k', '--key', required=True, help='Key to upload to')
def upload(ctx, profile, region, filename, bucket, key):
"""
Uploads a File to S3.
This might be a large CloudFormation template, or a Lambda zip file.
"""
try:
uploader = create_uploader(profile, region)
uploader.upload(filename, bucket, key)
except (TransferError, ValidationError) as e:
error(f'\nError: {e}')
exit(1)


if __name__ == '__main__':
cli()
cli(prog_name='stackmanager')
5 changes: 5 additions & 0 deletions stackmanager/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,8 @@ class ValidationError(Exception):
class StackError(Exception):
"""Exception thrown when there is an AWS Error managing a CloudFormation stack"""
pass


class TransferError(Exception):
"""Exception thrown when there is an AWS Error transferring files to S3"""
pass
43 changes: 43 additions & 0 deletions stackmanager/uploader.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import boto3
from boto3.exceptions import Boto3Error
from botocore.exceptions import ClientError
from stackmanager.exceptions import TransferError, ValidationError
from stackmanager.messages import info


class Uploader:
"""Utility for uploading files to S3"""

def __init__(self, client):
self._client = client

def upload(self, filename, bucket, key, acl='bucket-owner-full-control'):
"""
Uploads a local file to S3.
:param filename: Name of local file
:param bucket: S3 Bucket Name
:param key: S3 Key
:param acl: Object ACL, defaults to bucket-owner-full-control
:raises ValidationError: If local file does not exist
:raises TransferError: If there is an error uploading the file
"""
try:
self._client.upload_file(Filename=filename, Bucket=bucket, Key=key,
ExtraArgs={'ACL': acl})
info(f'\nUploaded {filename} to s3://{bucket}/{key}')
except FileNotFoundError:
raise ValidationError(f'File {filename} not found')
except (Boto3Error, ClientError) as e:
raise TransferError(e)


def create_uploader(profile, region):
"""
Create a new Uploader
:param profile: AWS Profile
:param region: AWS Region
:return: Configured Uploader
"""
session = boto3.Session(profile_name=profile, region_name=region)
client = session.client('s3')
return Uploader(client)

0 comments on commit 2e6f9e1

Please sign in to comment.