-
Notifications
You must be signed in to change notification settings - Fork 4.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
304 additions
and
0 deletions.
There are no files selected for viewing
123 changes: 123 additions & 0 deletions
123
aws/services/CloudFormation/MacrosExamples/Boto3/README.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
# How to install and use the Boto3 macro in your AWS account | ||
|
||
The `Boto3` macro adds the ability to create CloudFormation resources that represent operations performed by [boto3](http://boto3.readthedocs.io/). Each `Boto3` resource represents one function call. | ||
|
||
A typical use case for this macro might be, for example, to provide some basic configuration of resources. | ||
|
||
## Deploying | ||
|
||
1. You will need an S3 bucket to store the CloudFormation artifacts: | ||
* If you don't have one already, create one with `aws s3 mb s3://<bucket name>` | ||
|
||
2. Package the CloudFormation template. The provided template uses [the AWS Serverless Application Model](https://aws.amazon.com/about-aws/whats-new/2016/11/introducing-the-aws-serverless-application-model/) so must be transformed before you can deploy it. | ||
|
||
```shell | ||
aws cloudformation package \ | ||
--template-file macro.template \ | ||
--s3-bucket <your bucket name here> \ | ||
--output-template-file packaged.template | ||
``` | ||
|
||
3. Deploy the packaged CloudFormation template to a CloudFormation stack: | ||
|
||
```shell | ||
aws cloudformation deploy \ | ||
--stack-name boto3-macro \ | ||
--template-file packaged.template \ | ||
--capabilities CAPABILITY_IAM | ||
``` | ||
|
||
4. To test out the macro's capabilities, try launching the provided example template: | ||
```shell | ||
aws cloudformation deploy \ | ||
--stack-name boto3-macro-example \ | ||
--template-file example.template | ||
``` | ||
## Usage | ||
To make use of the macro, add `Transform: Boto3` to the top level of your CloudFormation template. | ||
Here is a trivial example template that adds a readme file to a new CodeCommit repository: | ||
```yaml | ||
Transform: Boto3 | ||
Resources: | ||
Repo: | ||
Type: AWS::CodeCommit::Repository | ||
Properties: | ||
RepositoryName: my-repo | ||
AddReadme: | ||
Type: Boto3::CodeCommit.put_file | ||
Mode: Create | ||
Properties: | ||
RepositoryName: !GetAtt Repo.Name | ||
BranchName: master | ||
FileContent: "Hello, world!" | ||
FilePath: README.md | ||
CommitMessage: Add a readme file | ||
Name: CloudFormation | ||
``` | ||
## Features | ||
### Resource type | ||
The resource `Type` is used to identify a [boto3 client](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/clients.html) and the method of that client to execute. | ||
The `Type` must start with `Boto3::` and be followed by the name of a client, a `.` and finally the name of a method. | ||
The client name will be converted to lower case so that you can use resource names that look similar to other CloudFormation resource types. | ||
Examples: | ||
* `Boto3::CodeCommit.put_file` | ||
* `Boto3::IAM.put_user_permissions_boundary` | ||
* `Boto3::EC2.create_snapshot` | ||
### Resource mode | ||
The resource may contain a `Mode` property which specifies whether the boto3 call should be made on `Create`, `Update`, `Delete` or any combination of those. | ||
The `Mode` may either be a string or a list of strings. For example: | ||
* `Mode: Create` | ||
* `Mode: Delete` | ||
* `Mode: [Create, Update]` | ||
### Resource properties | ||
The `Properties` of the resource will be passed to the specified boto3 method as arguments. The name of each property will be modified so that it started with a lower-case character so that you can use property names that look similar to other CloudFormation resource properties. | ||
### Controlling the order of execution | ||
You can use the standard CloudFormation property `DependsOn` when you need to ensure that your `Boto3` resources are executed in the correct order. | ||
## Examples | ||
The following resource: | ||
```yaml | ||
ChangeBinaryTypes: | ||
Type: Boto3::CloudFormation.execute_change_set | ||
Mode: [Create, Update] | ||
Properties: | ||
ChangeSetName: !Ref ChangeSet | ||
StackName: !Ref Stack | ||
``` | ||
will result in running the equivalent of the following: | ||
```python | ||
boto3.client("cloudformation").execute_change_set(changeSetName=<value of ChangeSet>, stackName=<value of StackName>) | ||
``` | ||
when the stack is created or updated. | ||
## Author | ||
[Steve Engledow](https://linkedin.com/in/stilvoid) | ||
Senior Solutions Builder | ||
Amazon Web Services |
18 changes: 18 additions & 0 deletions
18
aws/services/CloudFormation/MacrosExamples/Boto3/example.template
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
Transform: Boto3 | ||
|
||
Resources: | ||
Repo: | ||
Type: AWS::CodeCommit::Repository | ||
Properties: | ||
RepositoryName: my-repo | ||
|
||
AddReadme: | ||
Type: Boto3::CodeCommit.put_file | ||
Mode: Create | ||
Properties: | ||
RepositoryName: !GetAtt Repo.Name | ||
BranchName: master | ||
FileContent: "Hello, world" | ||
FilePath: README.md | ||
CommitMessage: Add another README.md | ||
Name: CloudFormation |
52 changes: 52 additions & 0 deletions
52
aws/services/CloudFormation/MacrosExamples/Boto3/lambda/macro.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
# Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"). You | ||
# may not use this file except in compliance with the License. A copy of | ||
# the License is located at | ||
# | ||
# http://aws.amazon.com/apache2.0/ | ||
# | ||
# or in the "license" file accompanying this file. This file is | ||
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF | ||
# ANY KIND, either express or implied. See the License for the specific | ||
# language governing permissions and limitations under the License. | ||
|
||
import os | ||
|
||
PREFIX = "Boto3::" | ||
|
||
LAMBDA_ARN = os.environ["LAMBDA_ARN"] | ||
|
||
def handle_template(request_id, template): | ||
for name, resource in template.get("Resources", {}).items(): | ||
if resource["Type"].startswith(PREFIX): | ||
resource.update({ | ||
"Type": "Custom::Boto3", | ||
"Version": "1.0", | ||
"Properties": { | ||
"ServiceToken": LAMBDA_ARN, | ||
"Mode": resource.get("Mode", ["Create", "Update"]), | ||
"Action": resource["Type"][len(PREFIX):], | ||
"Properties": resource.get("Properties", {}), | ||
}, | ||
}) | ||
|
||
if "Mode" in resource: | ||
del resource["Mode"] | ||
|
||
return template | ||
|
||
def handler(event, context): | ||
fragment = event["fragment"] | ||
status = "success" | ||
|
||
try: | ||
fragment = handle_template(event["requestId"], event["fragment"]) | ||
except Exception as e: | ||
status = "failure" | ||
|
||
return { | ||
"requestId": event["requestId"], | ||
"status": status, | ||
"fragment": fragment, | ||
} |
85 changes: 85 additions & 0 deletions
85
aws/services/CloudFormation/MacrosExamples/Boto3/lambda/resource.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
# Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"). You | ||
# may not use this file except in compliance with the License. A copy of | ||
# the License is located at | ||
# | ||
# http://aws.amazon.com/apache2.0/ | ||
# | ||
# or in the "license" file accompanying this file. This file is | ||
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF | ||
# ANY KIND, either express or implied. See the License for the specific | ||
# language governing permissions and limitations under the License. | ||
|
||
from urllib2 import build_opener, HTTPHandler, Request | ||
import base64 | ||
import boto3 | ||
import httplib | ||
import json | ||
|
||
def sendResponse(event, context, status, message): | ||
body = json.dumps({ | ||
"Status": status, | ||
"Reason": message, | ||
"StackId": event['StackId'], | ||
"RequestId": event['RequestId'], | ||
"LogicalResourceId": event['LogicalResourceId'], | ||
"PhysicalResourceId": event["ResourceProperties"]["Action"], | ||
"Data": {}, | ||
}) | ||
|
||
request = Request(event['ResponseURL'], data=body) | ||
request.add_header('Content-Type', '') | ||
request.add_header('Content-Length', len(body)) | ||
request.get_method = lambda: 'PUT' | ||
|
||
opener = build_opener(HTTPHandler) | ||
response = opener.open(request) | ||
|
||
def execute(action, properties): | ||
action = action.split(".") | ||
|
||
if len(action) != 2: | ||
return "FAILED", "Invalid boto3 call: {}".format(".".join(action)) | ||
|
||
client, function = action[0], action[1] | ||
|
||
try: | ||
client = boto3.client(client.lower()) | ||
except Exception as e: | ||
return "FAILED", "boto3 error: {}".format(e) | ||
|
||
try: | ||
function = getattr(client, function) | ||
except Exception as e: | ||
return "FAILED", "boto3 error: {}".format(e) | ||
|
||
properties = { | ||
key[0].lower() + key[1:]: value | ||
for key, value in properties.items() | ||
} | ||
|
||
try: | ||
function(**properties) | ||
except Exception as e: | ||
return "FAILED", "boto3 error: {}".format(e) | ||
|
||
return "SUCCESS", "Completed successfully" | ||
|
||
def handler(event, context): | ||
print("Received request:", json.dumps(event, indent=4)) | ||
|
||
request = event["RequestType"] | ||
properties = event["ResourceProperties"] | ||
|
||
if any(prop not in properties for prop in ("Action", "Properties")): | ||
print("Bad properties", properties) | ||
return sendResponse(event, context, "FAILED", "Missing required parameters") | ||
|
||
mode = properties["Mode"] | ||
|
||
if request == mode or request in mode: | ||
status, message = execute(properties["Action"], properties["Properties"]) | ||
return sendResponse(event, context, status, message) | ||
|
||
return sendResponse(event, context, "SUCCESS", "No action taken") |
26 changes: 26 additions & 0 deletions
26
aws/services/CloudFormation/MacrosExamples/Boto3/macro.template
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
Transform: AWS::Serverless-2016-10-31 | ||
|
||
Resources: | ||
ResourceFunction: | ||
Type: AWS::Serverless::Function | ||
Properties: | ||
Runtime: python2.7 | ||
CodeUri: lambda | ||
Handler: resource.handler | ||
Policies: PowerUserAccess | ||
|
||
MacroFunction: | ||
Type: AWS::Serverless::Function | ||
Properties: | ||
Runtime: python3.6 | ||
CodeUri: lambda | ||
Handler: macro.handler | ||
Environment: | ||
Variables: | ||
LAMBDA_ARN: !GetAtt ResourceFunction.Arn | ||
|
||
Macro: | ||
Type: AWS::CloudFormation::Macro | ||
Properties: | ||
Name: Boto3 | ||
FunctionName: !GetAtt MacroFunction.Arn |