|
| 1 | + |
| 2 | +# AWS CDK Python Dev Guide |
| 3 | + |
| 4 | +This project is a template that's intended to serve as a guide for working with CDK in Python. |
| 5 | + |
| 6 | +This project is based on the [aws-cdk-js-dev-guide](https://github.com/therightstuff/aws-cdk-js-dev-guide). |
| 7 | + |
| 8 | +## Tooling setup for local AWS development |
| 9 | + |
| 10 | +### Preamble |
| 11 | + |
| 12 | +It is valuable and necessary to go through the following steps to familiarize yourself with the tools. |
| 13 | + |
| 14 | +- create programmatic user in IAM with admin permissions |
| 15 | +- if you're using visual studio code (recommended), [configure aws toolkit](https://docs.aws.amazon.com/toolkit-for-vscode/latest/userguide/setup-toolkit.html) |
| 16 | +- set up credentials with the profile id "default" |
| 17 | +- get 12 digit account id from My Account in console |
| 18 | +- follow [the CDK hello world tutorial](https://docs.aws.amazon.com/cdk/latest/guide/getting_started.html#hello_world_tutorial) |
| 19 | + |
| 20 | +### Tool Versions |
| 21 | + |
| 22 | +CDK, like SAM, tends to be updated frequently with breaking changes. Prior to committing changes, please ensure that you are using the latest versions and that everything is building and running correctly. |
| 23 | + |
| 24 | +### CDK Initialization |
| 25 | + |
| 26 | +The first step to creating a CDK project is initializing it with `cdk init app` (eg. `cdk init app --language python`), and a CDK project cannot be initialized if the project directory isn't empty. If you would like to use an existing project (like this one) as a template, bear in mind that you will have to rename the stack in multiple locations and it would probably be safer and easier to create a new project and copy and paste in the bits you need (estimated time: 20-30 minutes if you're not familiar with the project structure). |
| 27 | + |
| 28 | +## Python setup |
| 29 | + |
| 30 | +This project is set up like a standard Python project. The initialization |
| 31 | +process also creates a virtualenv within this project, stored under the `.venv` |
| 32 | +directory. To create the virtualenv it assumes that there is a `python3` |
| 33 | +(or `python` for Windows) executable in your path with access to the `venv` |
| 34 | +package. If for any reason the automatic creation of the virtualenv fails, |
| 35 | +you can create the virtualenv manually. |
| 36 | + |
| 37 | +To manually create a virtualenv on MacOS and Linux: |
| 38 | + |
| 39 | +```bash |
| 40 | +python3 -m venv .venv |
| 41 | +``` |
| 42 | + |
| 43 | +After the init process completes and the virtualenv is created, you can use the following |
| 44 | +step to activate your virtualenv. |
| 45 | + |
| 46 | +```bash |
| 47 | +source .venv/bin/activate |
| 48 | +``` |
| 49 | + |
| 50 | +If you are a Windows platform, you would activate the virtualenv like this: |
| 51 | + |
| 52 | +```bash |
| 53 | +.venv\Scripts\activate.bat |
| 54 | +``` |
| 55 | + |
| 56 | +Once the virtualenv is activated, you can install the required dependencies. |
| 57 | + |
| 58 | +```bash |
| 59 | +pip install -r requirements.txt |
| 60 | +``` |
| 61 | + |
| 62 | +At this point you can now synthesize the CloudFormation template for this code. |
| 63 | + |
| 64 | +```bash |
| 65 | +cdk synth |
| 66 | +``` |
| 67 | + |
| 68 | +To add additional dependencies, for example other CDK libraries, just add |
| 69 | +them to your `setup.py` file and rerun the `pip install -r requirements.txt` |
| 70 | +command. |
| 71 | + |
| 72 | +## Useful commands |
| 73 | + |
| 74 | +- `cdk ls` list all stacks in the app |
| 75 | +- `cdk synth` emits the synthesized CloudFormation template(s) |
| 76 | +- `cdk deploy` deploy this stack to your default AWS account/region |
| 77 | +- `cdk diff` compare deployed stack with current state |
| 78 | + |
| 79 | +### Stack definition |
| 80 | + |
| 81 | +The stack definition is located in the `/aws_cdk_python_dev_guide` folder, this is where the stack is configured for deployment. |
| 82 | + |
| 83 | +See [AWS CDK API documentation](https://docs.aws.amazon.com/cdk/api/latest/docs/aws-construct-library.html) for reference. |
| 84 | + |
| 85 | +#### Lambda Functions |
| 86 | + |
| 87 | +Lambda functions are defined in the `handlers` directory, and include the following samples: |
| 88 | + |
| 89 | +- `simple`: a stateless function |
| 90 | + |
| 91 | +Lambda functions MUST return responses in the following format: |
| 92 | + |
| 93 | +```python |
| 94 | +{ |
| 95 | + "statusCode": 200, |
| 96 | + "headers": {}, |
| 97 | + "body": json.dumps({...}) |
| 98 | +} |
| 99 | +``` |
| 100 | + |
| 101 | +#### API Gateway Integrations |
| 102 | + |
| 103 | +When you create a `RestApi` object, the `.root` resource defaults to `/prod/`. You can add HTTP method handlers to the root, or add resource objects and add method handlers to those. To add a resource parameter, simply add a resource enclosed in curly braces (`{}`) and this will be accessible in the `event` object as `event.get("pathParameters")`. |
| 104 | + |
| 105 | +Querystring parameters will be available in the `event` object as `event.get("queryStringParameters")`. |
| 106 | + |
| 107 | +NOTE: it is not possible to rename a path parameter, as cdk will attempt to deploy the new resource before removing the old one and it cannot deploy two resources with the same path structure. The workaround suggested on [the serverless issue thread](https://github.com/serverless/serverless/issues/3785) is to comment out the resource definition, deploy, then uncomment it and deploy again. |
| 108 | + |
| 109 | +`aws_cdk_python_dev_guide/aws_cdk_python_dev_guide_stack.py`: |
| 110 | + |
| 111 | +```python |
| 112 | +# Enable CORS for all resources of an api |
| 113 | +api = RestApi(self, 'api-name', { |
| 114 | + default_cors_preflight_options={ |
| 115 | + # array containing an origin, or Cors.ALL_ORIGINS |
| 116 | + allow_origins: [ cors_origin ], |
| 117 | + # array of methods eg. [ 'OPTIONS', 'GET', 'POST', 'PUT', 'DELETE' ] |
| 118 | + allow_methods: Cors.ALL_METHODS, |
| 119 | + } |
| 120 | +}) |
| 121 | + |
| 122 | +# OR |
| 123 | + |
| 124 | +# Enable CORS for a specific api resource |
| 125 | +api2 = RestApi(self, 'api2-name'); |
| 126 | +api2_objects = api2.root.addResource('objects'); |
| 127 | +api2_objects.add_cors_preflight({ |
| 128 | + # array containing an origin, or Cors.ALL_ORIGINS |
| 129 | + allow_origins: [ cors_origin ], |
| 130 | + # array of methods eg. [ 'OPTIONS', 'GET', 'POST', 'PUT', 'DELETE' ] |
| 131 | + allow_methods: Cors.ALL_METHODS, |
| 132 | +}) |
| 133 | +``` |
| 134 | + |
| 135 | +`handlers/myhandler/index.py`: |
| 136 | + |
| 137 | +```python |
| 138 | +return { |
| 139 | + "statusCode": 200, |
| 140 | + "headers": { |
| 141 | + 'Access-Control-Allow-Origin': os.environ['CORS_ORIGIN'], |
| 142 | + 'Access-Control-Allow-Credentials': True, |
| 143 | + }, |
| 144 | + "body": json.dumps({ "success": True }) |
| 145 | +}) |
| 146 | +``` |
| 147 | + |
| 148 | +NOTE: This project defines an origin per stack in the `./stages.json` file, which requires a modification to the `AwsCdkPythonDevGuideStack` signature / kwargs. This is not a CDK requirement, you should configure it in any way that suits your purposes. |
| 149 | + |
| 150 | +For more details see [https://docs.aws.amazon.com/cdk/api/latest/docs/aws-apigateway-readme.html](https://docs.aws.amazon.com/cdk/api/latest/docs/aws-apigateway-readme.html) and [https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-apigateway.CorsOptions.html](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-apigateway.CorsOptions.html). |
| 151 | + |
| 152 | +### Deployment |
| 153 | + |
| 154 | +By default, CDK deploys stacks that are [environment-agnostic](https://docs.aws.amazon.com/cdk/latest/guide/environments.html). To enable environment-agnostic deployments, run `cdk bootstrap` before `cdk deploy`, but configuring specific regions is probably the safer practice. |
| 155 | + |
| 156 | +To deploy to specific regions, update the `./regions.json` file with the desired region and account numbers. |
| 157 | + |
| 158 | +An example for stack configuration has been provided in `./stages.json`. |
| 159 | + |
| 160 | +To deploy a stack, `cdk deploy <stack name>` (wildcards are supported). |
| 161 | + |
| 162 | +If you don't want to review each set of changes, use the `--require-approval=never` option (not recommended). |
| 163 | + |
| 164 | +The `Outputs` displayed at the end of the process include the API Gateway endpoints. These can be used as-is for the example lambda functions. |
| 165 | + |
| 166 | +### Redeploying a Stack |
| 167 | + |
| 168 | +One of the great advantages of using CDK is that updating a stack is as simple as running the `cdk deploy <stack name>` again. |
| 169 | + |
| 170 | +### Debugging |
| 171 | + |
| 172 | +Testing a lambda function via the API Gateway interface is unlikely to report useful error details. If a function is not behaving correctly or is failing, go to your CloudWatch dashboard and find the log group for the function. |
| 173 | + |
| 174 | +### Deleting a Stack |
| 175 | + |
| 176 | +If for whatever reason you decide you want to delete a stack in its entirety, install the [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html) and run `aws cloudformation delete-stack --stack-name <stack name> --region <region name>`. |
0 commit comments