├── .github ├── PULL_REQUEST_TEMPLATE.md └── workflows │ └── pr-ci.yaml ├── .gitignore ├── .pre-commit-config.yaml ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── NOTICE ├── README.md ├── docs ├── README.md ├── images │ ├── VS-JsonSettings.png │ ├── VSCode.gif │ └── VSCodeYAML.mp4 ├── pycharm │ └── instructions.md ├── tool │ └── instructions.md └── vscode │ └── instructions.md ├── pom.xml └── src ├── main ├── java │ └── aws │ │ └── cfn │ │ └── codegen │ │ ├── AttributeType.java │ │ ├── CfnSpecification.java │ │ ├── CfnSpecificationException.java │ │ ├── PropertyType.java │ │ ├── ResourceType.java │ │ ├── SingleCfnSpecification.java │ │ ├── SpecificationLoader.java │ │ └── json │ │ ├── Codegen.java │ │ ├── Config.java │ │ ├── GroupSpec.java │ │ ├── Main.java │ │ └── SchemaDraft.java └── resources │ ├── Intrinsics.json │ ├── Schema.template │ └── config.yml └── test └── java └── aws └── cfn └── codegen ├── GroupSpecTest.java ├── MainTest.java └── resources.txt /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | *Issue #, if available:* 2 | 3 | *Description of changes:* 4 | 5 | 6 | By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license. 7 | -------------------------------------------------------------------------------- /.github/workflows/pr-ci.yaml: -------------------------------------------------------------------------------- 1 | on: [push, pull_request] 2 | jobs: 3 | build: 4 | runs-on: ubuntu-latest 5 | strategy: 6 | matrix: 7 | java: [8, 11] 8 | steps: 9 | - uses: actions/checkout@v2 10 | - uses: actions/setup-java@v1 11 | with: 12 | java-version: ${{ matrix.java }} 13 | - uses: actions/setup-python@v2 14 | with: 15 | python-version: 3 16 | - run: | 17 | pip3 install --quiet pre-commit 18 | pre-commit run --all-files 19 | mvn clean verify --no-transfer-progress 20 | echo 'settings: 21 | regions: [test] 22 | output: cfn-schemas' > cfg.yml 23 | java -jar target/aws-cloudformation-template-schema-1.0-SNAPSHOT-jar-with-dependencies.jar --config-file cfg.yml 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | .idea/ 3 | .DS_Store 4 | *.iml 5 | *.class 6 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/pre-commit/pre-commit-hooks 3 | rev: v2.4.0 4 | hooks: 5 | - id: check-case-conflict 6 | - id: detect-private-key 7 | - id: end-of-file-fixer 8 | - id: mixed-line-ending 9 | args: 10 | - --fix=lf 11 | - id: trailing-whitespace 12 | - id: pretty-format-json 13 | args: 14 | - --autofix 15 | - --indent=2 16 | - --no-sort-keys 17 | - id: check-merge-conflict 18 | - id: check-yaml 19 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | ## Code of Conduct 2 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 3 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 4 | opensource-codeofconduct@amazon.com with any additional questions or comments. 5 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | Thank you for your interest in contributing to our project. Whether it's a bug report, new feature, correction, or additional 4 | documentation, we greatly value feedback and contributions from our community. 5 | 6 | Please read through this document before submitting any issues or pull requests to ensure we have all the necessary 7 | information to effectively respond to your bug report or contribution. 8 | 9 | 10 | ## Reporting Bugs/Feature Requests 11 | 12 | We welcome you to use the GitHub issue tracker to report bugs or suggest features. 13 | 14 | When filing an issue, please check [existing open](https://github.com/awslabs/aws-cloudformation-template-schema/issues), or [recently closed](https://github.com/awslabs/aws-cloudformation-template-schema/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aclosed%20), issues to make sure somebody else hasn't already 15 | reported the issue. Please try to include as much information as you can. Details like these are incredibly useful: 16 | 17 | * A reproducible test case or series of steps 18 | * The version of our code being used 19 | * Any modifications you've made relevant to the bug 20 | * Anything unusual about your environment or deployment 21 | 22 | 23 | ## Contributing via Pull Requests 24 | Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that: 25 | 26 | 1. You are working against the latest source on the *master* branch. 27 | 2. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already. 28 | 3. You open an issue to discuss any significant work - we would hate for your time to be wasted. 29 | 30 | To send us a pull request, please: 31 | 32 | 1. Fork the repository. 33 | 2. Modify the source; please focus on the specific change you are contributing. If you also reformat all the code, it will be hard for us to focus on your change. 34 | 3. Ensure local tests pass. 35 | 4. Commit to your fork using clear commit messages. 36 | 5. Send us a pull request, answering any default questions in the pull request interface. 37 | 6. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation. 38 | 39 | GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and 40 | [creating a pull request](https://help.github.com/articles/creating-a-pull-request/). 41 | 42 | 43 | ## Finding contributions to work on 44 | Looking at the existing issues is a great way to find something to contribute on. As our projects, by default, use the default GitHub issue labels (enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any ['help wanted'](https://github.com/awslabs/aws-cloudformation-template-schema/labels/help%20wanted) issues is a great place to start. 45 | 46 | 47 | ## Code of Conduct 48 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 49 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 50 | opensource-codeofconduct@amazon.com with any additional questions or comments. 51 | 52 | 53 | ## Security issue notifications 54 | If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/). Please do **not** create a public github issue. 55 | 56 | 57 | ## Licensing 58 | 59 | See the [LICENSE](https://github.com/awslabs/aws-cloudformation-template-schema/blob/master/LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution. 60 | 61 | We may ask you to sign a [Contributor License Agreement (CLA)](http://en.wikipedia.org/wiki/Contributor_License_Agreement) for larger changes. 62 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | AWS Cloudformation Template Schema 2 | Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## AWS CloudFormation Template Schema 2 | 3 | The CloudFormation template schema is intended to improve the authoring experience for our customers. 4 | It is a simple code process which converts our existing Resource Specifications files into a 5 | [JSON Schema](https://json-schema.org) formatted document. This schema can be integrated into many publicly available IDEs 6 | such as Visual Studio Code & PyCharm to provide inline syntax checking and code completion. 7 | 8 | ## Key Features 9 | 10 | 1. Complete type-safe template authoring with IntelliSense-based completion 11 | 1. Support for both YAML and JSON templates 12 | 1. Errors flagged for missing required properties 13 | 1. Integrated deep links to CloudFormation documentation for the resource or template section you are editing 14 | 15 | ## What does an integration look like? 16 | 17 | Here is a VSCode setup integration example 18 | ![VSCode](docs/images/VSCode.gif) 19 | 20 | ## How do I set it up? 21 | 22 | #### VS Code 23 | 24 | For [VS Code](https://code.visualstudio.com/) please follow the [setup/guidelines](docs/vscode/instructions.md) or install the pre-configured [CloudFormation Linter VS Code extension](https://github.com/aws-cloudformation/aws-cfn-lint-visual-studio-code) 25 | 26 | #### PyCharm 27 | 28 | For [PyCharm](https://www.jetbrains.com/pycharm/) please follow the [setup/guidelines](docs/pycharm/instructions.md) 29 | 30 | 31 | ## How do I build and run the tool? 32 | 33 | See [instructions](docs/tool/instructions.md) which describes how to run the tool locally, to generate specifications for only subset of resources or AWS regions. 34 | 35 | 36 | ## License 37 | 38 | This library is licensed under the Apache 2.0 License. 39 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | ../README.md -------------------------------------------------------------------------------- /docs/images/VS-JsonSettings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-cloudformation/cloudformation-template-schema/5d7815b14fd533c15c30f9046a76cdcb89afd32a/docs/images/VS-JsonSettings.png -------------------------------------------------------------------------------- /docs/images/VSCode.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-cloudformation/cloudformation-template-schema/5d7815b14fd533c15c30f9046a76cdcb89afd32a/docs/images/VSCode.gif -------------------------------------------------------------------------------- /docs/images/VSCodeYAML.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-cloudformation/cloudformation-template-schema/5d7815b14fd533c15c30f9046a76cdcb89afd32a/docs/images/VSCodeYAML.mp4 -------------------------------------------------------------------------------- /docs/pycharm/instructions.md: -------------------------------------------------------------------------------- 1 | PyCharm instructions 2 | ------ 3 | 4 | **Install PyCharm** 5 | 6 | 1. Install PyCharm [code binary](https://www.jetbrains.com/pycharm/download/). 7 | 2. Start PyCharm, on macOS press CMD+ and type __pycharm__ 8 | 9 | **JSON/YAML Setup** 10 | 11 | 1. Open __Preferences__ 12 | 1. Navigate to __Languages and Frameworks__ > __Schemas and DTDs__ > __JSON Schema Mappings__ 13 | 1. Add new Mapping (__Ctrl+N__) 14 | 1. Name the Mapping (e.g; "CFN Template Schema") 15 | 1. Enter a Schema URL (e.g; `https://s3.amazonaws.com/cfn-resource-specifications-us-east-1-prod/schemas/2.15.0/all-spec.json`) 16 | 1. Add a mapping to a folder or file path pattern (e.g; `"*-template.json`) 17 | 1. Select the appropriate Schema Version: __JSON schema version 7__ 18 | 1. Click __OK__ to save. 19 | 1. Create new file with the extension specified in the mapping (e.g; `my-app-template.json`) 20 | 21 | Gotchas 22 | ------ 23 | 24 | 1. PyCharm does not provide the `description` context on mouse-hover (which other IDEs do) 25 | 26 | Troubleshooting 27 | ------ 28 | **JSON Schema not found or contain error in 'all-spec.json': Can not load code model for JSON Schema file 'all-spec.json'** 29 | 30 | PyCharm uses the `idea.max.intellisense.filesize` platform property to set the maximum size of files for which PyCharm provides code assistance and to load a JSON schema. 31 | 32 | By default this property is set to `2500` kilobytes. 33 | 34 | In order to load a schema bigger than this size, you have to edit this property to a number greater than the size of your schema, for example `5000` kilobytes. In order to do that go to `Help | Edit Custom Properties` and add the following line: `idea.max.intellisense.filesize=5000`. 35 | 36 | Restart PyCharm, you can now load the file. 37 | 38 | This restriction only applies to local file, if for whatever reason you can't edit this file you can setup a local webserver (For example with `python -m SimpleHTTPServer`) and serve your schema file through http. 39 | -------------------------------------------------------------------------------- /docs/tool/instructions.md: -------------------------------------------------------------------------------- 1 | ## Requirements to build and run the tool 2 | 3 | - JDK >= 1.8, 4 | - Maven >= 3.x 5 | 6 | ## Building 7 | 8 | To build the project use standard `mvn` commands. Build standard package; 9 | 10 | ``` 11 | mvn clean package 12 | ``` 13 | 14 | This will build into a single executable assembly. 15 | 16 | ## Running the tool 17 | 18 | After build, the tool can be executed using the following syntax; 19 | 20 | ```sh 21 | java -jar target/aws-cloudformation-template-schema-1.0-SNAPSHOT-jar-with-dependencies.jar 22 | ``` 23 | 24 | ## Configuration 25 | 26 | The tool can be used to generate multiple groups of schemas as needed for particular purposes. Here is a sample 27 | configuration file that generates for only us-east-2 region. It create 2 groups in addition to the default bundle 28 | based on the config file show below in the local directory ./cfn-schemas 29 | 30 | ```yaml 31 | settings: 32 | regions: [us-east-2] 33 | output: cfn-schemas 34 | 35 | groups: 36 | serverless: 37 | includes: 38 | - AWS::ApiGateway.* 39 | - AWS::Lambda.* 40 | - AWS::IAM.* 41 | 42 | 3tierAsgApp: 43 | includes: 44 | - AWS::ElasticLoadBalancingV2.* 45 | - AWS::RDS.* 46 | - AWS::AutoScal.* 47 | - AWS::IAM.* 48 | 49 | ``` 50 | 51 | To generate your own subset, save the file as cfg.yml and then run with 52 | 53 | ```sh 54 | java -jar target/aws-cloudformation-template-schema-1.0-SNAPSHOT-jar-with-dependencies.jar --config-file cfg.yml 55 | ``` 56 | 57 | The files will be generated inside $PWD/cfn-schemas/us-east-2/\*-spec.json 58 | -------------------------------------------------------------------------------- /docs/vscode/instructions.md: -------------------------------------------------------------------------------- 1 | VSCode instructions 2 | 3 | **Install VSCode** 4 | 5 | 1. Install VS [code binary](https://code.visualstudio.com/). Here are links to [Windows](https://aka.ms/win32-user-stable), [macOS](ihttps://go.microsoft.com/fwlink/?LinkID=620882), [linux-debian](ihttps://go.microsoft.com/fwlink/?LinkID=760868) 6 | 2. Start VSCode, on macOS press CMD+ and type __code__ 7 | 3. Install [YAML support](https://marketplace.visualstudio.com/items?itemName=redhat.vscode-yaml) for VSCode. Here is the [github repo](https://github.com/redhat-developer/vscode-yaml) 8 | 9 | **JSON/YAML Setup** 10 | 11 | 1. Edit "user.settings" on macOS CMD+, or click on Code -> Preferences -> Settings 12 | 2. In the search bar search for __json.schemas__ ![VS-Code-Setup](../images/VS-JsonSettings.png) 13 | 3. Click on __settings.json__ 14 | 4. Cut-n-paste the following settings 15 | ```json 16 | { 17 | "[yaml]": { 18 | "editor.insertSpaces": true, 19 | "editor.tabSize": 2, 20 | "editor.quickSuggestions": { 21 | "other": true, 22 | "comments": false, 23 | "strings": true 24 | }, 25 | "editor.autoIndent": true 26 | }, 27 | "editor.renderWhitespace": "all", 28 | "editor.tabSize": 2, 29 | "editor.autoIndent": true, 30 | "yaml.format.enable": true, 31 | "yaml.trace.server": "verbose", 32 | "yaml.customTags": [ 33 | "!And scalar", 34 | "!If scalar", 35 | "!Not", 36 | "!Equals scalar", 37 | "!Or scalar", 38 | "!FindInMap scalar", 39 | "!Base64", 40 | "!Cidr", 41 | "!Ref", 42 | "!Sub", 43 | "!GetAtt sequence", 44 | "!GetAZs", 45 | "!ImportValue sequence", 46 | "!Select sequence", 47 | "!Split sequence", 48 | "!Join sequence" 49 | ], 50 | "json.schemas": [ 51 | { 52 | "fileMatch": [ 53 | "*-template.json" 54 | ], 55 | "url": "https://s3.amazonaws.com/cfn-resource-specifications-us-east-1-prod/schemas/2.15.0/all-spec.json" 56 | } 57 | ], 58 | "yaml.schemas": { 59 | "https://s3.amazonaws.com/cfn-resource-specifications-us-east-1-prod/schemas/2.15.0/all-spec.json": "*-template.yaml" 60 | } 61 | } 62 | ``` 63 | 5. Create new file with the extension specified in the mapping (e.g; my-app-template.json, or my-app-template.yaml). VSCode will use the mapping to determine which files should be treated as CloudFormation templates. 64 | 65 | **YAML Gotchas** 66 | 67 | YAML is very whitespace sensitive for code completion. YAML LSP support does not deal with whitespace correctly. Here are tips to follow along if code completion isn't working as desired 68 | 69 | 1. Ensure to get rid of all white spaces below the line you are editing (https://github.com/redhat-developer/vscode-yaml/issues/141) 70 | 2. Remember that you _can not_ edit in between. Editing towards the end is the only one works. You still will have some partial results but experience is sub-par. This is true for all json schemas 71 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 4.0.0 6 | 7 | aws.cfn.codegen 8 | aws-cloudformation-template-schema 9 | 1.0-SNAPSHOT 10 | 11 | aws-cloudformation-template-schema 12 | https://github.com/awslabs/aws-cloudformation-template-schema 13 | 14 | 15 | UTF-8 16 | 1.8 17 | 1.8 18 | 19 | 20 | 21 | 22 | 23 | org.apache.logging.log4j 24 | log4j-core 25 | 2.17.1 26 | 27 | 28 | 29 | junit 30 | junit 31 | 4.13.1 32 | test 33 | 34 | 35 | 36 | org.projectlombok 37 | lombok 38 | 1.16.22 39 | 40 | 41 | 42 | com.fasterxml.jackson.core 43 | jackson-databind 44 | 2.14.1 45 | 46 | 47 | 48 | com.fasterxml.jackson.core 49 | jackson-core 50 | 2.14.1 51 | 52 | 53 | 54 | 55 | com.fasterxml.jackson.dataformat 56 | jackson-dataformat-yaml 57 | 2.14.1 58 | 59 | 60 | 61 | com.github.spullara.mustache.java 62 | compiler 63 | 0.9.5 64 | 65 | 66 | 67 | args4j 68 | args4j 69 | 2.33 70 | 71 | 72 | 73 | 74 | com.google.guava 75 | guava 76 | [30.0-jre,) 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | maven-clean-plugin 88 | 3.0.0 89 | 90 | 91 | 92 | maven-specifications-plugin 93 | 3.0.2 94 | 95 | 96 | maven-compiler-plugin 97 | 3.7.0 98 | 99 | 100 | maven-surefire-plugin 101 | 2.22.0 102 | 103 | 104 | maven-jar-plugin 105 | 3.0.2 106 | 107 | 108 | maven-install-plugin 109 | 2.5.2 110 | 111 | 112 | maven-deploy-plugin 113 | 2.8.2 114 | 115 | 116 | 117 | 118 | 119 | org.apache.maven.plugins 120 | maven-compiler-plugin 121 | 122 | 8 123 | 8 124 | 125 | 126 | 127 | org.apache.maven.plugins 128 | maven-assembly-plugin 129 | 3.1.0 130 | 131 | 132 | package 133 | 134 | single 135 | 136 | 137 | 138 | 139 | 140 | aws.cfn.codegen.json.Main 141 | 142 | 143 | 144 | 145 | jar-with-dependencies 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | -------------------------------------------------------------------------------- /src/main/java/aws/cfn/codegen/AttributeType.java: -------------------------------------------------------------------------------- 1 | package aws.cfn.codegen; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | 5 | import lombok.Data; 6 | import lombok.EqualsAndHashCode; 7 | import lombok.NoArgsConstructor; 8 | 9 | import java.util.Optional; 10 | 11 | /** 12 | * Describes the higher level Attributes in CFN. 13 | * @see getListOrMapPrimitiveType() { 50 | return Optional.ofNullable(primitiveItemType); 51 | } 52 | 53 | public Optional getComplexType() { 54 | // If type is primitive then type == null 55 | if ("List".equals(type) || "Map".equals(type)) { 56 | return Optional.ofNullable(itemType); 57 | } 58 | // Json shows up in type but CFN calls this primitive type. Let us honor it 59 | return Optional.ofNullable("Json".equals(type) ? null : type); 60 | } 61 | 62 | public String getPrimitiveType() { 63 | return primitiveType; 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/aws/cfn/codegen/CfnSpecification.java: -------------------------------------------------------------------------------- 1 | package aws.cfn.codegen; 2 | 3 | import lombok.Data; 4 | import lombok.EqualsAndHashCode; 5 | import lombok.ToString; 6 | 7 | import java.util.AbstractCollection; 8 | import java.util.HashMap; 9 | import java.util.HashSet; 10 | import java.util.Map; 11 | import java.util.Set; 12 | 13 | /** 14 | * A simple class the represents CFN resource specification. Properties defined within CFN specification 15 | * are also defined exactly like a Resource. 16 | * 17 | * @see findDiff(CfnSpecification toSpec) { 55 | return resourceTypes.entrySet().stream() 56 | .filter(entry -> toSpec.resourceTypes.containsKey(entry.getKey())) 57 | .collect( 58 | HashSet::new, 59 | (diffSet, e) -> { 60 | if (!toSpec.getResourceTypes().get(e.getKey()).equals(e)) { 61 | Difference diff = new Difference(); 62 | diff.setFromType(e.getValue()); 63 | diff.setFromVersion(resourceSpecificationVersion); 64 | diff.setToType(toSpec.getResourceTypes().get(e.getKey())); 65 | diff.setToVersion(toSpec.getResourceSpecificationVersion()); 66 | diffSet.add(diff); 67 | } 68 | }, 69 | AbstractCollection::addAll); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/aws/cfn/codegen/CfnSpecificationException.java: -------------------------------------------------------------------------------- 1 | package aws.cfn.codegen; 2 | 3 | public class CfnSpecificationException extends RuntimeException { 4 | public CfnSpecificationException(String msg) { 5 | super(msg); 6 | } 7 | 8 | public CfnSpecificationException(String msg, Throwable chain) { 9 | super(msg, chain); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/aws/cfn/codegen/PropertyType.java: -------------------------------------------------------------------------------- 1 | package aws.cfn.codegen; 2 | 3 | import lombok.Data; 4 | import lombok.EqualsAndHashCode; 5 | import lombok.NoArgsConstructor; 6 | 7 | /** 8 | * This defines a CFN's Resource's Property Type. 9 | * 10 | * @see regions = config.getSpecifications(); 52 | URI cfnResourceSpecification = regions.get(region); 53 | if (this.config.getSettings().getSingle()) { 54 | SingleCfnSpecification single = new SpecificationLoader() 55 | .loadSingleResourceSpecification( 56 | cfnResourceSpecification.toURL()); 57 | spec = new CfnSpecification(); 58 | spec.setPropertyTypes(single.getPropertyTypes()); 59 | spec.setResourceTypes(single.getResourceType()); 60 | spec.setResourceSpecificationVersion(single.getResourceSpecificationVersion()); 61 | } 62 | else { 63 | spec = new SpecificationLoader() 64 | .loadSpecification(cfnResourceSpecification.toURL()); 65 | } 66 | spec.validate(); 67 | return spec; 68 | } 69 | 70 | private Map loadGroupsOutputLocation(String region) throws IOException { 71 | File output = config.getSettings().getOutput(); 72 | Map groups = config.getGroups(); 73 | if (!output.exists() && !output.mkdirs()) { 74 | throw new IOException("Can not create out directory to write " + output); 75 | } 76 | 77 | File parent = new File(output, region); 78 | if (!parent.exists() && !parent.mkdirs()) { 79 | throw new IOException("Can not create directory for region " + region 80 | + " at " + parent); 81 | } 82 | 83 | Map groupSchemas = new HashMap<>(groups.size()); 84 | for (Map.Entry each: groups.entrySet()) { 85 | File out = new File(parent, each.getKey() + "-spec.json"); 86 | if (!out.exists() && !out.createNewFile()) { 87 | throw new IOException("Can not create output file to write " + out); 88 | } 89 | groupSchemas.put(each.getKey(), out); 90 | } 91 | return groupSchemas; 92 | } 93 | 94 | private Map loadGroupDefinitions() { 95 | return config.getGroups().entrySet().stream(). 96 | collect(Collectors.toMap( 97 | Map.Entry::getKey, 98 | ign -> mapper.createObjectNode(), 99 | (first, ign) -> first)); 100 | } 101 | 102 | private String draft() { 103 | return config.getSettings().getDraft().getLocation(); 104 | } 105 | 106 | private void addToPerGroupRoots(Map, ObjectNode> definitions, 107 | Map groupSpecDefinitions) { 108 | for (Map.Entry, ObjectNode> each: definitions.entrySet()) { 109 | List key = each.getKey(); 110 | String name = key.get(0); 111 | String defnName = key.get(1); 112 | this.config.getGroups().entrySet().stream() 113 | .filter(e -> e.getValue().isIncluded(name)) 114 | .map(e -> groupSpecDefinitions.get(e.getKey())) 115 | .forEach(root -> root.replace(defnName, each.getValue())); 116 | } 117 | } 118 | 119 | private void generatePerGroup(List definitionNames, 120 | Map groupSchemas, 121 | Map groupSpecDefinitions, 122 | CfnSpecification specification) { 123 | 124 | final Boolean includeIntrinsics = this.config.getSettings().getIncludeIntrinsics(); 125 | final String intrinsics = includeIntrinsics != null && includeIntrinsics ? 126 | intrinsics() : ""; 127 | 128 | groupSpecDefinitions.entrySet().stream() 129 | // Add resources block to each 130 | .map(e -> { 131 | ObjectNode definitions = e.getValue(); 132 | 133 | // Add alternative custom resources 134 | ObjectNode customResource = definitions.putObject("altCustomResource"); 135 | customResource.put("type", "object"); 136 | ObjectNode custProperties = customResource.putObject("properties"); 137 | ObjectNode custType = custProperties.putObject("Type"); 138 | custType.put("type", "string"); 139 | custType.put("pattern", "Custom::[A-Za-z0-9]+"); 140 | custType.put("maxLength", 60); 141 | ObjectNode custProp = custProperties.putObject("Properties"); 142 | custProp.put("type", "object"); 143 | ArrayNode required = customResource.putArray("required"); 144 | required.add("Type"); 145 | required.add("Properties"); 146 | customResource.put("additionalProperties", false); 147 | addDependsOn(custProperties); 148 | 149 | ObjectNode resourcesDefnSide = definitions.putObject("resources"); 150 | resourcesDefnSide.put("type", "object"); 151 | resourcesDefnSide.put("additionalProperties", false); 152 | resourcesDefnSide.put("minProperties", 1); 153 | ObjectNode patternProps = resourcesDefnSide.putObject("patternProperties"); 154 | ObjectNode resourceProps = patternProps.putObject("^[a-zA-Z0-9]{1,255}$"); 155 | ArrayNode anyOf = resourceProps.putArray("oneOf"); 156 | ObjectNode ref = anyOf.addObject(); 157 | ref.put("$ref", "#/definitions/altCustomResource"); 158 | for (String eachDefn: definitionNames) { 159 | if (definitions.has(eachDefn)) { 160 | ref = anyOf.addObject(); 161 | ref.put("$ref", "#/definitions/" + eachDefn); 162 | } 163 | } 164 | return e; 165 | }) 166 | // Write each output file 167 | .forEach(e -> { 168 | try { 169 | Map variables = new HashMap<>(5); 170 | variables.put("draft", draft()); 171 | String res = 172 | mapper.writerWithDefaultPrettyPrinter().writeValueAsString(e.getValue()); 173 | variables.put("intrinsics", intrinsics); 174 | variables.put("resources", res.substring(1, res.length() - 1)); 175 | String description = "CFN JSON specification generated from version " + 176 | specification.getResourceSpecificationVersion(); 177 | variables.put("description", description); 178 | Mustache cfnSchema = new DefaultMustacheFactory().compile("Schema.template"); 179 | cfnSchema.execute(new OutputStreamWriter( 180 | new FileOutputStream(groupSchemas.get(e.getKey())), 181 | StandardCharsets.UTF_8 182 | ), variables).flush(); 183 | } 184 | catch (IOException ex) { 185 | throw new RuntimeException(ex); 186 | } 187 | }); 188 | } 189 | 190 | @SuppressWarnings("unchecked") 191 | public void generate() throws Exception { 192 | config.getSettings().getRegions().stream() 193 | .map(region -> { 194 | try { 195 | logger.debug("Loading specification for {}", region); 196 | return new Object[] { 197 | region, 198 | loadSpecification(region), 199 | loadGroupsOutputLocation(region), 200 | loadGroupDefinitions() 201 | }; 202 | } 203 | catch (Exception e) { 204 | logger.fatal(String.format("Loading specification for %s failed", region), e); 205 | throw new RuntimeException(e); 206 | } 207 | }) 208 | .forEach(result -> { 209 | String region = (String)result[0]; 210 | logger.debug("Starting generation for {} specification", region); 211 | CfnSpecification spec = (CfnSpecification) result[1]; 212 | Map locations = (Map) result[2]; 213 | Map defns = (Map) result[3]; 214 | try { 215 | generate(spec, locations, defns); 216 | } 217 | catch (Exception e) { 218 | logger.fatal(String.format("Generation for %s specification failed", region), e); 219 | throw new RuntimeException(e); 220 | } 221 | }); 222 | } 223 | 224 | private void generate(CfnSpecification specification, 225 | Map groupSchemas, 226 | Map groupSpecDefinitions) 227 | throws Exception { 228 | 229 | final Map resources = specification.getResourceTypes(); 230 | final Map properties = specification.getPropertyTypes(); 231 | final Set propertyNames = properties.keySet(); 232 | final List resDefns = new ArrayList<>(resources.size()); 233 | List sorted= new ArrayList<>(resources.keySet()); 234 | Collections.sort(sorted); 235 | 236 | Map, ObjectNode> definitions = new LinkedHashMap<>(sorted.size()); 237 | for (final String name: sorted) { 238 | ResourceType type = null; 239 | try { 240 | type = resources.get(name); 241 | String defnName = name.replace("::", "_"); 242 | resDefns.add(defnName); 243 | ObjectNode typeDefn = mapper.createObjectNode(); 244 | handleType(typeDefn, defnName, name, type, true, propertyNames); 245 | definitions.put(Arrays.asList(name, defnName), typeDefn); 246 | logger.debug("Processed type {}", name); 247 | } 248 | catch (Exception e) 249 | { 250 | // ignore and emit warning for malformed types in the spec 251 | if (type != null) { 252 | logger.error("An error occurred processing type {}", name); 253 | } 254 | else { 255 | throw e; 256 | } 257 | } 258 | } 259 | addToPerGroupRoots(definitions, groupSpecDefinitions); 260 | 261 | sorted = new ArrayList<>(properties.keySet()); 262 | Collections.sort(sorted); 263 | definitions = new LinkedHashMap<>(sorted.size()); 264 | for (final String name: sorted) { 265 | ResourceType type = properties.get(name); 266 | String[] parts = name.split("\\."); 267 | if (parts.length > 1) { 268 | String defnName = parts[0].replace("::", "_"); 269 | String propName = parts[1]; 270 | ObjectNode typeDefn = mapper.createObjectNode(); 271 | handleType(typeDefn, defnName, propName, type, false, propertyNames); 272 | List key = Arrays.asList(name, defnName + "_" + propName); 273 | definitions.put(key, typeDefn); 274 | } 275 | else { 276 | // equals 1, no namespacing case 277 | String defnName = name.replace("::", "_"); 278 | ObjectNode typeDefn = mapper.createObjectNode(); 279 | handleType(typeDefn, defnName, defnName, type, false, propertyNames); 280 | List key = Arrays.asList(name, defnName); 281 | definitions.put(key, typeDefn); 282 | } 283 | 284 | } 285 | addToPerGroupRoots(definitions, groupSpecDefinitions); 286 | generatePerGroup(resDefns, groupSchemas, groupSpecDefinitions, specification); 287 | } 288 | 289 | private final static Map> PrimitiveMappings = 290 | new HashMap>() {{ 291 | put("String", () -> "string"); 292 | put("Number", () -> "integer"); 293 | put("Integer", () -> "integer"); 294 | put("Float", () -> "number"); 295 | put("Double", () -> "number"); 296 | put("Long", () -> "integer"); 297 | put("Json", () -> "object"); 298 | put("Boolean", () -> "boolean"); 299 | put("Timestamp", () -> "string"); 300 | 301 | }}; 302 | 303 | private void addDependsOn(ObjectNode addTo) { 304 | ObjectNode dependsOn = addTo.putObject("DependsOn"); 305 | ArrayNode dependsOnTypes = dependsOn.putArray("type"); 306 | dependsOnTypes.add("string"); 307 | dependsOnTypes.add("array"); 308 | ObjectNode items = dependsOn.putObject("items"); 309 | items.put("type", "string"); 310 | } 311 | 312 | private void handleType(ObjectNode typeDefn, 313 | String defnName, 314 | String name, 315 | ResourceType type, 316 | boolean isResource, 317 | Set propertyNames) { 318 | typeDefn.put("type", "object"); 319 | typeDefn.put("description", type.getDocumentation()); 320 | ObjectNode properties, innerProps = null; 321 | if (isResource) { 322 | ObjectNode resProps = typeDefn.putObject("properties"); 323 | ObjectNode enumType = resProps.putObject("Type"); 324 | enumType.put("description", type.getDocumentation()); 325 | enumType.put("type", "string"); 326 | ArrayNode array = enumType.putArray("enum"); 327 | array.add(name); 328 | 329 | for (String policyName: new String[]{"DeletionPolicy", "UpdateReplacePolicy"}) { 330 | ObjectNode policy = resProps.putObject(policyName); 331 | policy.put("description", "https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-attribute-" + policyName.toLowerCase() + ".html"); 332 | policy.put("type", "string"); 333 | ArrayNode policyArray = policy.putArray("enum"); 334 | policyArray.add("Delete").add("Retain").add("Snapshot"); 335 | } 336 | 337 | for (String attributeName: new String[]{"Metadata", "CreationPolicy", "UpdatePolicy"}) { 338 | ObjectNode attribute = resProps.putObject(attributeName); 339 | attribute.put("description", "https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-attribute-" + attributeName.toLowerCase() + ".html"); 340 | attribute.put("type", "object"); 341 | } 342 | 343 | innerProps = resProps.putObject("Properties"); 344 | innerProps.put("type", "object"); 345 | properties = innerProps.putObject("properties"); 346 | // Add DependsOn 347 | addDependsOn(resProps); 348 | } 349 | else { 350 | properties = typeDefn.putObject("properties"); 351 | } 352 | final List required = new ArrayList<>(5); 353 | type.getProperties().forEach( 354 | (propName, propType) -> { 355 | ObjectNode each = properties.putObject(propName); 356 | if (propType.isObjectType()) { 357 | each.put("$ref", "#/definitions/" + 358 | (propertyNames.contains(propType.getType()) ? propType.getType() : 359 | defnName + "_" + propType.getType())); 360 | } 361 | else { 362 | each.put("description", propType.getDocumentation()); 363 | if (propType.isPrimitive()) { 364 | addPrimitiveType(each, propType.getPrimitiveType()); 365 | } else if (propType.isCollectionType()) { 366 | each.put("type", "array"); 367 | ObjectNode itemType = each.putObject("items"); 368 | if (propType.isContainerInnerTypePrimitive()) { 369 | addPrimitiveType(itemType, propType.getPrimitiveItemType()); 370 | } else { 371 | itemType.put("$ref", "#/definitions/" + 372 | (propertyNames.contains(propType.getItemType()) ? propType.getItemType() : 373 | defnName + "_" + propType.getItemType())); 374 | } 375 | Boolean duplicates = propType.getDuplicatesAllowed(); 376 | if (duplicates != null && !duplicates) { 377 | each.put("uniqueItems", true); 378 | } 379 | each.put("minItems", 0); 380 | } else { 381 | // Map Type 382 | each.put("type", "object"); 383 | ObjectNode mapProps = each.putObject("patternProperties"); 384 | ObjectNode patPropKeyValue = mapProps.putObject("[a-zA-Z0-9]+"); 385 | if (propType.isContainerInnerTypePrimitive()) { 386 | addPrimitiveType(patPropKeyValue, propType.getPrimitiveItemType()); 387 | } else { 388 | patPropKeyValue.put("$ref", "#/definitions/" + 389 | (propertyNames.contains(propType.getItemType()) ? propType.getItemType() : 390 | defnName + "_" + propType.getItemType())); 391 | } 392 | } 393 | Boolean requiredB = propType.getRequired(); 394 | if (requiredB != null && requiredB) { 395 | required.add(propName); 396 | } 397 | } 398 | } 399 | ); 400 | 401 | if (isResource) { 402 | if (!required.isEmpty()) { 403 | ArrayNode array = innerProps.putArray("required"); 404 | required.forEach(array::add); 405 | } 406 | innerProps.put("additionalProperties", false); 407 | ArrayNode array = typeDefn.putArray("required"); 408 | array.add("Type"); 409 | if (!required.isEmpty()) { 410 | array.add("Properties"); 411 | } 412 | } 413 | else { 414 | if (!required.isEmpty()) { 415 | ArrayNode array = typeDefn.putArray("required"); 416 | required.forEach(array::add); 417 | } 418 | } 419 | typeDefn.put("additionalProperties", false); 420 | } 421 | 422 | private void addPrimitiveType(ObjectNode each, String propType) { 423 | if (config.getSettings().getDraft() == SchemaDraft.draft07) { 424 | String type = PrimitiveMappings.get(propType).get(); 425 | 426 | if (config.getSettings().getIncludeIntrinsics()) { 427 | if (!type.equals("string")) { 428 | ArrayNode types = each.putArray("anyOf"); 429 | types.addObject().put("type", type); 430 | types.addObject().put("$ref", "#/definitions/Expression"); 431 | } else { 432 | each.put("$ref", "#/definitions/Expression"); 433 | } 434 | } else { 435 | ArrayNode types = each.putArray("type"); 436 | types.add(type); 437 | if (!type.equals("object")) { 438 | types.add("object"); 439 | } 440 | } 441 | } 442 | else { 443 | each.put("type", 444 | PrimitiveMappings.get(propType).get()); 445 | } 446 | } 447 | 448 | private String intrinsics() { 449 | ClassLoader loader = Thread.currentThread().getContextClassLoader(); 450 | loader = loader == null ? getClass().getClassLoader() : loader; 451 | ObjectMapper mapper = new ObjectMapper(); 452 | try { 453 | InputStream is = loader.getResourceAsStream("Intrinsics.json"); 454 | JsonNode root = mapper.readTree(is); 455 | String intrinsics = mapper.writer().withDefaultPrettyPrinter().writeValueAsString(root); 456 | return intrinsics.substring(1, intrinsics.length() - 1).concat(","); 457 | } catch (IOException e) { 458 | e.printStackTrace(); 459 | } 460 | 461 | return ""; 462 | } 463 | } 464 | -------------------------------------------------------------------------------- /src/main/java/aws/cfn/codegen/json/Config.java: -------------------------------------------------------------------------------- 1 | package aws.cfn.codegen.json; 2 | 3 | import com.fasterxml.jackson.annotation.JsonCreator; 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | import com.google.common.collect.Sets; 6 | 7 | import java.io.File; 8 | import java.net.URI; 9 | import java.util.LinkedHashMap; 10 | import java.util.Map; 11 | import java.util.Objects; 12 | import java.util.Optional; 13 | import java.util.Set; 14 | 15 | /** 16 | * This represent the configuration that dictate {@link Codegen} to determine specification 17 | * by regions and generate appropriate template schemas based on the groups that we specified 18 | * By default if the tool is not provided with a configuration, it loads the default configuration 19 | * file that is bundled with that package. See config.yml 20 | * 21 | * @see GroupSpec 22 | */ 23 | @lombok.Getter 24 | @lombok.ToString 25 | @lombok.EqualsAndHashCode 26 | public final class Config { 27 | 28 | public static Builder builder() { 29 | return new Builder(null); 30 | } 31 | 32 | public static Builder builder(Config existing) { 33 | return new Builder(Objects.requireNonNull(existing)); 34 | } 35 | 36 | public static class Builder { 37 | private SchemaDraft draft = SchemaDraft.draft07; 38 | private File outputDir; 39 | private Set regions; 40 | private boolean singleResourceSpec = false; 41 | private boolean includeIntrinsics = true; 42 | private final Map regionSpecs = new LinkedHashMap<>(12); 43 | private final Map groups = new LinkedHashMap<>(5); 44 | 45 | private Builder(Config existing) { 46 | if (existing != null) { 47 | mergeOverride(existing); 48 | } 49 | } 50 | 51 | public Builder mergeOverride(Config other) { 52 | Objects.requireNonNull(other); 53 | Settings settings = other.getSettings(); 54 | if (settings != null) { 55 | this.draft = settings.getDraft() != null ? settings.getDraft() : this.draft; 56 | this.outputDir = settings.getOutput() != null ? settings.getOutput() : this.outputDir; 57 | this.regions = settings.getRegions() != null ? settings.getRegions() : this.regions; 58 | this.singleResourceSpec = settings.getSingle() != null ? settings.getSingle() : this.singleResourceSpec; 59 | this.includeIntrinsics = settings.getIncludeIntrinsics() != null ? settings.getIncludeIntrinsics() : 60 | this.includeIntrinsics; 61 | } 62 | this.regionSpecs.putAll(other.getSpecifications()); 63 | this.groups.putAll(other.getGroups()); 64 | return this; 65 | } 66 | 67 | public Builder withJsonSchema(SchemaDraft draft) { 68 | this.draft = draft; 69 | return this; 70 | } 71 | 72 | public Builder withRegionSpec(String region, String location) { 73 | return withRegionSpec(region, URI.create(location)); 74 | } 75 | 76 | public Builder withRegionSpec(String region, URI location) { 77 | regionSpecs.put( 78 | Objects.requireNonNull(region), 79 | location); 80 | return this; 81 | } 82 | 83 | public Builder addRegion(String region) { 84 | this.regions.add(Objects.requireNonNull(region)); 85 | return this; 86 | } 87 | 88 | public Builder addRegions(Set regions) { 89 | this.regions.addAll(regions); 90 | return this; 91 | } 92 | 93 | public Builder setRegions(Set regions) { 94 | this.regions = Objects.requireNonNull(regions); 95 | return this; 96 | } 97 | 98 | public Builder withOutputDirectory(File dir) { 99 | this.outputDir = Objects.requireNonNull(dir); 100 | return this; 101 | } 102 | 103 | public Builder isSingleResourceSpec(boolean single) { 104 | this.singleResourceSpec = single; 105 | return this; 106 | } 107 | 108 | public Builder withIntrinsics(boolean includeIntrinsics) { 109 | this.includeIntrinsics = includeIntrinsics; 110 | return this; 111 | } 112 | 113 | public Builder withGroup(String grpName, GroupSpec spec) { 114 | groups.put(grpName, spec); 115 | return this; 116 | } 117 | 118 | public Config build() { 119 | return new Config( 120 | regionSpecs, 121 | new Settings( 122 | draft, 123 | regions, 124 | outputDir, 125 | singleResourceSpec, 126 | includeIntrinsics 127 | ), 128 | groups 129 | ); 130 | } 131 | 132 | } 133 | 134 | @lombok.Getter 135 | @lombok.ToString 136 | @lombok.EqualsAndHashCode 137 | public static class Settings { 138 | private final SchemaDraft draft; 139 | private final Set regions; 140 | private final File output; 141 | private final Boolean single; 142 | private final Boolean includeIntrinsics; 143 | 144 | @JsonCreator 145 | public Settings(@JsonProperty("draft") SchemaDraft draft, 146 | @JsonProperty("regions") Set regions, 147 | @JsonProperty("output") File output, 148 | @JsonProperty("single") Boolean single, 149 | @JsonProperty("intrinsics") Boolean includeIntrinsics) { 150 | this.draft = draft; 151 | this.regions = regions == null ? Sets.newHashSet("us-east-1") : regions; 152 | this.output = output; 153 | this.single = single == null ? false : single; 154 | this.includeIntrinsics = includeIntrinsics == null ? false : includeIntrinsics; 155 | } 156 | } 157 | 158 | private final Map groups; 159 | private final Settings settings; 160 | private final Map specifications; 161 | @JsonCreator 162 | public Config(@JsonProperty("specifications") final Map specifications, 163 | @JsonProperty("settings") final Settings settings, 164 | @JsonProperty("groups") final Map groups) { 165 | this.specifications = specifications != null ? specifications : new LinkedHashMap<>(1); 166 | this.settings = settings; 167 | this.groups = groups != null ? groups : new LinkedHashMap<>(); 168 | validateRegionSpecs(); 169 | validateGroups(); 170 | } 171 | 172 | private void validateRegionSpecs() { 173 | if (settings != null && !specifications.isEmpty()) { 174 | for (String r: settings.getRegions()) { 175 | if (!specifications.containsKey(r)) { 176 | throw new IllegalArgumentException("No regions mapping was found " + settings.getRegions()); 177 | } 178 | } 179 | } 180 | } 181 | 182 | private void validateGroups() { 183 | if (groups.isEmpty()) { 184 | GroupSpec spec = GroupSpec.includesOnly("all", "AWS.*"); 185 | groups.put(spec.getGroupName(), spec); 186 | } 187 | 188 | // Merge as needed 189 | GroupSpec defaultGrpSpec = groups.containsKey("default") ? 190 | groups.remove("default") : 191 | GroupSpec.includesOnly("default", "Tag.*"); 192 | Optional> defaultIncludes = Optional.ofNullable(defaultGrpSpec.getIncludes()); 193 | Optional> defaultExcludes = Optional.ofNullable(defaultGrpSpec.getExcludes()); 194 | 195 | // merge default and then compile the specifications 196 | groups.entrySet().stream() 197 | .map(e -> { 198 | GroupSpec grp = e.getValue(); 199 | grp.setGroupName(e.getKey()); 200 | grp.setIncludes( 201 | Optional.ofNullable(grp.getIncludes()) 202 | .map(s -> 203 | defaultIncludes. 204 | map(ds -> { s.addAll(ds); return s; }) 205 | .orElse(s) 206 | ) 207 | .orElseGet(defaultGrpSpec::getIncludes)); 208 | grp.setExcludes( 209 | Optional.ofNullable(grp.getExcludes()) 210 | .map(s -> 211 | defaultExcludes 212 | .map(ds -> { s.addAll(ds); return s; }) 213 | .orElse(s) 214 | ) 215 | .orElseGet(defaultGrpSpec::getExcludes) 216 | ); 217 | return e; 218 | }) 219 | .map(Map.Entry::getValue) 220 | .forEach(GroupSpec::compile); 221 | } 222 | } 223 | -------------------------------------------------------------------------------- /src/main/java/aws/cfn/codegen/json/GroupSpec.java: -------------------------------------------------------------------------------- 1 | package aws.cfn.codegen.json; 2 | 3 | import com.google.common.collect.Sets; 4 | 5 | import java.util.ArrayList; 6 | import java.util.Iterator; 7 | import java.util.List; 8 | import java.util.Objects; 9 | import java.util.Set; 10 | import java.util.regex.Pattern; 11 | 12 | /** 13 | * GroupSpec allows for generating the schema for only a subset of resources grouped together 14 | * for a specific purpose. See the included resource file config.yml for a set of default groupings 15 | * like networking (for VPC, Subnet and related stuff), serverless, for Lambda, ApiGateway and IAM 16 | * etc. 17 | */ 18 | @lombok.EqualsAndHashCode 19 | @lombok.ToString 20 | public class GroupSpec { 21 | 22 | public static GroupSpec includesOnly(String name, String... includes) { 23 | return new GroupSpec(name, Sets.newHashSet(includes), null); 24 | } 25 | 26 | public static GroupSpec excludesOnly(String name, String... excludes) { 27 | return new GroupSpec(name, null, Sets.newHashSet(excludes)); 28 | } 29 | 30 | @lombok.Setter 31 | @lombok.Getter 32 | private Set includes; 33 | @lombok.Setter 34 | @lombok.Getter 35 | private Set excludes; 36 | @lombok.Setter 37 | @lombok.Getter 38 | private String groupName; 39 | private List incPatterns = new ArrayList<>(5); 40 | private List exPatterns = new ArrayList<>(5); 41 | 42 | public GroupSpec() {} 43 | public GroupSpec(String name, Set includes, Set excludes) { 44 | groupName = Objects.requireNonNull(name); 45 | this.includes = includes; 46 | this.excludes = excludes; 47 | } 48 | 49 | public void compile() { 50 | if (includes != null) { 51 | for (String each: includes) { 52 | incPatterns.add(Pattern.compile(each)); 53 | } 54 | } 55 | 56 | if (excludes != null) { 57 | for (String each: excludes) { 58 | exPatterns.add(Pattern.compile(each)); 59 | } 60 | } 61 | } 62 | 63 | public boolean isIncluded(String resourceType) { 64 | boolean included = false; 65 | for (Iterator each = incPatterns.iterator(); 66 | !included && each.hasNext();) { 67 | // Matcher is never null 68 | included = each.next().matcher(resourceType).matches(); 69 | } 70 | 71 | boolean excluded = false; 72 | for (Iterator each = exPatterns.iterator(); 73 | !excluded && each.hasNext(); ) { 74 | // Matcher is never null 75 | excluded = each.next().matcher(resourceType).matches(); 76 | } 77 | 78 | return included && !excluded; 79 | } 80 | 81 | } 82 | -------------------------------------------------------------------------------- /src/main/java/aws/cfn/codegen/json/Main.java: -------------------------------------------------------------------------------- 1 | package aws.cfn.codegen.json; 2 | 3 | import com.fasterxml.jackson.databind.ObjectMapper; 4 | import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; 5 | import com.google.common.collect.Sets; 6 | import org.kohsuke.args4j.CmdLineParser; 7 | import org.kohsuke.args4j.Option; 8 | 9 | import java.io.File; 10 | import java.net.URI; 11 | import java.util.Set; 12 | 13 | public final class Main { 14 | 15 | @Option(name = "--cfn-spec-url", 16 | usage = "URL location of the CFN Resource specification see locations at " + 17 | "https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-resource-specification.html") 18 | private URI location; 19 | 20 | @Option(name = "--aws-region", 21 | usage = "AWS Region this resource specification belongs to e.g. us-east-2, See regions at " + 22 | "https://docs.aws.amazon.com/general/latest/gr/rande.html") 23 | private String region; 24 | 25 | @Option(name = "--json-schema-version", usage = "Support values are [draft04, draft07]") 26 | private SchemaDraft draft; 27 | 28 | @Option(name = "--output-dir", 29 | usage = "output directory where the schemas will be generated. e.g. /tmp, schemas will be /tmp//*-spec.json") 30 | private File outputDir; 31 | 32 | @Option(name = "--config-file", 33 | usage = "configuration file for specifying groups. See sample config.yml included") 34 | private File configFile; 35 | 36 | @Option(name = "--single", 37 | usage = "Use this flag is you are generating this for single resource") 38 | private Boolean single; 39 | 40 | @Option(name = "--merge", 41 | usage = "merge with the default configuration that we have") 42 | private boolean merge = true; 43 | 44 | @Option(name = "--intrinsics", 45 | usage = "Use this flag to include Intrinsic Functions in the schema") 46 | private Boolean intrinsics; 47 | 48 | private Main() {} 49 | 50 | private void execute() throws Exception { 51 | final ObjectMapper mapper = new ObjectMapper(new YAMLFactory()); 52 | ClassLoader loader = Thread.currentThread().getContextClassLoader(); 53 | loader = loader == null ? getClass().getClassLoader() : loader; 54 | Config config = configFile != null ? 55 | mapper.readValue(configFile, Config.class) : 56 | mapper.readValue(loader.getResource("config.yml"), Config.class); 57 | 58 | if (merge && configFile != null) { 59 | Config bundled = mapper.readValue(loader.getResource("config.yml"), Config.class); 60 | Config.Builder builder = Config.builder(bundled); 61 | builder.mergeOverride(config); 62 | config = builder.build(); 63 | } 64 | 65 | // are their overriding args sent in outside config file 66 | Config.Settings settings = config.getSettings(); 67 | Set regions = this.region != null ? Sets.newHashSet(this.region) : settings.getRegions(); 68 | File outputDir = this.outputDir != null ? this.outputDir : settings.getOutput(); 69 | SchemaDraft draft = this.draft != null ? this.draft : settings.getDraft(); 70 | boolean single = this.single != null ? this.single : settings.getSingle(); 71 | boolean intrinsics = this.intrinsics != null ? this.intrinsics : settings.getIncludeIntrinsics(); 72 | 73 | config = Config.builder(config) 74 | .withJsonSchema(draft) 75 | .withOutputDirectory(outputDir) 76 | .setRegions(regions) 77 | .isSingleResourceSpec(single) 78 | .withIntrinsics(intrinsics) 79 | .build(); 80 | 81 | new Codegen(config).generate(); 82 | } 83 | 84 | public static void main(String[] args) throws Exception { 85 | Main main = new Main(); 86 | CmdLineParser parser = new CmdLineParser(main); 87 | 88 | parser.parseArgument(args); 89 | main.execute(); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/main/java/aws/cfn/codegen/json/SchemaDraft.java: -------------------------------------------------------------------------------- 1 | package aws.cfn.codegen.json; 2 | 3 | public enum SchemaDraft { 4 | draft04("http://json-schema.org/draft-04/schema#"), 5 | draft07("http://json-schema.org/draft-07/schema#"); 6 | 7 | public String getLocation() { 8 | return location; 9 | } 10 | 11 | private final String location; 12 | SchemaDraft(String location) { 13 | this.location = location; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/resources/Intrinsics.json: -------------------------------------------------------------------------------- 1 | { 2 | "Condition": { 3 | "$comment": "You can use intrinsic functions, such as Fn::If, Fn::Equals, and Fn::Not, to conditionally create stack resources. These conditions are evaluated based on input parameters that you declare when you create or update a stack. After you define all your conditions, you can associate them with resources or resource properties in the Resources and Outputs sections of a template.", 4 | "type": "object", 5 | "patternProperties": { 6 | "^[a-zA-Z0-9._-]{1,255}$": { 7 | "$ref": "#/definitions/ConditionalExpression" 8 | } 9 | }, 10 | "additionalProperties": false 11 | }, 12 | "ConditionalExpression": { 13 | "$comment": "Intrinsic function token expression or literal value", 14 | "anyOf": [ 15 | { 16 | "$comment": "Literal value", 17 | "type": "string" 18 | }, 19 | { 20 | "$ref": "#/definitions/FnAnd" 21 | }, 22 | { 23 | "$ref": "#/definitions/FnEquals" 24 | }, 25 | { 26 | "$ref": "#/definitions/FnIf" 27 | }, 28 | { 29 | "$ref": "#/definitions/FnNot" 30 | }, 31 | { 32 | "$ref": "#/definitions/FnOr" 33 | }, 34 | { 35 | "$ref": "#/definitions/FnFindInMap" 36 | }, 37 | { 38 | "$ref": "#/definitions/FnRef" 39 | } 40 | ] 41 | }, 42 | "Expression": { 43 | "$comment": "Intrinsic function token expression or literal value", 44 | "type": [ 45 | "string", 46 | "object" 47 | ], 48 | "anyOf": [ 49 | { 50 | "$comment": "Literal string value", 51 | "type": "string" 52 | }, 53 | { 54 | "$ref": "#/definitions/FnBase64" 55 | }, 56 | { 57 | "$ref": "#/definitions/FnCidr" 58 | }, 59 | { 60 | "$ref": "#/definitions/FnFindInMap" 61 | }, 62 | { 63 | "$ref": "#/definitions/FnGetAtt" 64 | }, 65 | { 66 | "$ref": "#/definitions/FnGetAZs" 67 | }, 68 | { 69 | "$ref": "#/definitions/FnImportValue" 70 | }, 71 | { 72 | "$ref": "#/definitions/FnJoin" 73 | }, 74 | { 75 | "$ref": "#/definitions/FnRef" 76 | }, 77 | { 78 | "$ref": "#/definitions/FnSelect" 79 | }, 80 | { 81 | "$ref": "#/definitions/FnSplit" 82 | }, 83 | { 84 | "$ref": "#/definitions/FnSub" 85 | } 86 | ] 87 | }, 88 | "FnBase64": { 89 | "type": "object", 90 | "properties": { 91 | "Fn::Base64": { 92 | "description": "https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-base64.html", 93 | "$ref": "#/definitions/Expression" 94 | } 95 | }, 96 | "additionalProperties": false 97 | }, 98 | "FnCidr": { 99 | "type": "object", 100 | "properties": { 101 | "Fn::Cidr": { 102 | "description": "https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-cidr.html", 103 | "type": "array", 104 | "items": [ 105 | { 106 | "$comment": "The user-specified CIDR address block to be split into smaller CIDR blocks.", 107 | "$ref": "#/definitions/Expression" 108 | }, 109 | { 110 | "$comment": "The number of CIDRs to generate. Valid range is between 1 and 256.", 111 | "type": "integer", 112 | "minimum": 1, 113 | "maximum": 256 114 | }, 115 | { 116 | "$comment": "The number of subnet bits for the CIDR. For example, specifying a value \"8\" for this parameter will create a CIDR with a mask of \"/24\".", 117 | "type": "integer", 118 | "minimum": 1, 119 | "maximum": 128 120 | } 121 | ], 122 | "minItems": 2, 123 | "maxItems": 3 124 | } 125 | }, 126 | "additionalProperties": false 127 | }, 128 | "FnFindInMap": { 129 | "type": "object", 130 | "properties": { 131 | "Fn::FindInMap": { 132 | "description": "https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-findinmap.html", 133 | "type": "array", 134 | "items": [ 135 | { 136 | "$comment": "The logical name of a mapping declared in the Mappings section that contains the keys and values.", 137 | "type": "string" 138 | }, 139 | { 140 | "$comment": "The top-level key name. Its value is a list of key-value pairs.", 141 | "$ref": "#/definitions/Expression" 142 | }, 143 | { 144 | "$comment": "The second-level key name, which is set to one of the keys from the list assigned to TopLevelKey.", 145 | "$ref": "#/definitions/Expression" 146 | } 147 | ], 148 | "minItems": 3, 149 | "maxItems": 3 150 | } 151 | }, 152 | "additionalProperties": false 153 | }, 154 | "FnGetAtt": { 155 | "type": "object", 156 | "properties": { 157 | "Fn::GetAtt": { 158 | "description": "https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-getatt.html", 159 | "type": "array", 160 | "items": [ 161 | { 162 | "$comment": "The logical name (also called logical ID) of the resource that contains the attribute that you want.", 163 | "$ref": "#/definitions/Expression" 164 | }, 165 | { 166 | "$comment": "The name of the resource-specific attribute whose value you want. See the resource's reference page for details about the attributes available for that resource type.", 167 | "type": "string" 168 | } 169 | ] 170 | } 171 | }, 172 | "additionalProperties": false 173 | }, 174 | "FnGetAZs": { 175 | "type": "object", 176 | "properties": { 177 | "Fn::GetAZs": { 178 | "description": "https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-getavailabilityzones.html", 179 | "$ref": "#/definitions/Expression" 180 | } 181 | }, 182 | "additionalProperties": false 183 | }, 184 | "FnImportValue": { 185 | "type": "object", 186 | "properties": { 187 | "Fn::ImportValue": { 188 | "description": "https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-importvalue.html", 189 | "$comment": "The stack output value that you want to import.", 190 | "$ref": "#/definitions/Expression" 191 | } 192 | }, 193 | "additionalProperties": false 194 | }, 195 | "FnJoin": { 196 | "type": "object", 197 | "properties": { 198 | "Fn::Join": { 199 | "description": "https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-join.html", 200 | "type": "array", 201 | "items": [ 202 | { 203 | "$comment": "The value you want to occur between fragments. The delimiter will occur between fragments only. It will not terminate the final value.", 204 | "$ref": "#/definitions/Expression" 205 | }, 206 | { 207 | "$comment": "The list of values you want combined.", 208 | "type": "array" 209 | } 210 | ], 211 | "minItems": 2 212 | } 213 | }, 214 | "additionalProperties": false 215 | }, 216 | "FnRef": { 217 | "anyOf": [ 218 | { 219 | "description": "https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-ref.html", 220 | "type": "object", 221 | "properties": { 222 | "Fn::Ref": { 223 | "$ref": "#/definitions/Expression" 224 | } 225 | }, 226 | "additionalProperties": false 227 | }, 228 | { 229 | "description": "https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-ref.html", 230 | "type": "object", 231 | "properties": { 232 | "Ref": { 233 | "$ref": "#/definitions/Expression" 234 | } 235 | }, 236 | "additionalProperties": false 237 | } 238 | ] 239 | }, 240 | "FnSelect": { 241 | "type": "object", 242 | "properties": { 243 | "Fn::Select": { 244 | "description": "https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-select.html", 245 | "type": "array", 246 | "items": [ 247 | { 248 | "$comment": "The index of the object to retrieve. This must be a value from zero to N-1, where N represents the number of elements in the array.", 249 | "type": [ 250 | "integer", 251 | "string" 252 | ] 253 | }, 254 | { 255 | "$comment": "The list of objects to select from. This list must not be null, nor can it have null entries.", 256 | "type": "array", 257 | "items": { 258 | "type": "string" 259 | }, 260 | "minItems": 1 261 | } 262 | ] 263 | } 264 | }, 265 | "additionalProperties": false 266 | }, 267 | "FnSplit": { 268 | "type": "object", 269 | "properties": { 270 | "Fn::Split": { 271 | "description": "https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-split.html", 272 | "type": "array", 273 | "items": [ 274 | { 275 | "$comment": "A string value that determines where the source string is divided.", 276 | "type": "string" 277 | }, 278 | { 279 | "$comment": "The string value that you want to split.", 280 | "type": "string" 281 | } 282 | ] 283 | } 284 | }, 285 | "additionalProperties": false 286 | }, 287 | "FnSub": { 288 | "type": "object", 289 | "properties": { 290 | "Fn::Sub": { 291 | "description": "https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-sub.html", 292 | "oneOf": [ 293 | { 294 | "type": "string" 295 | }, 296 | { 297 | "type": "array", 298 | "items": [ 299 | { 300 | "$comment": "A string with variables that AWS CloudFormation substitutes with their associated values at runtime. Write variables as ${MyVarName}. Variables can be template parameter names, resource logical IDs, resource attributes, or a variable in a key-value map. If you specify only template parameter names, resource logical IDs, and resource attributes, don't specify a key-value map.\nIf you specify template parameter names or resource logical IDs, such as ${InstanceTypeParameter}, AWS CloudFormation returns the same values as if you used the Ref intrinsic function. If you specify resource attributes, such as ${MyInstance.PublicIp}, AWS CloudFormation returns the same values as if you used the Fn::GetAtt intrinsic function.\nTo write a dollar sign and curly braces (${}) literally, add an exclamation point (!) after the open curly brace, such as ${!Literal}. AWS CloudFormation resolves this text as ${Literal}.", 301 | "type": "string" 302 | }, 303 | { 304 | "$comment": "The name of a variable that you included in the String parameter.", 305 | "type": "object", 306 | "patternProperties": { 307 | "^[a-zA-Z0-9._-]{1,255}$": { 308 | "$comment": "The value that AWS CloudFormation substitutes for the associated variable name at runtime.", 309 | "$ref": "#/definitions/Expression" 310 | } 311 | }, 312 | "minProperties": 1 313 | } 314 | ], 315 | "minItems": 1 316 | } 317 | ] 318 | } 319 | }, 320 | "additionalProperties": false 321 | }, 322 | "FnTransform": { 323 | "type": "object", 324 | "properties": { 325 | "Fn::Transform": { 326 | "description": "https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-transform.html", 327 | "type": "object", 328 | "properties": { 329 | "Name": { 330 | "$comment": "The name of the macro you want to perform the processing.", 331 | "$ref": "#/definitions/Condition" 332 | }, 333 | "Parameters": { 334 | "$comment": "The list parameters, specified as key-value pairs, to pass to the macro.", 335 | "type": "object" 336 | } 337 | } 338 | } 339 | } 340 | }, 341 | "FnAnd": { 342 | "type": "object", 343 | "properties": { 344 | "Fn::And": { 345 | "description": "https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-conditions.html#intrinsic-function-reference-conditions-and", 346 | "type": "array", 347 | "items": { 348 | "$ref": "#/definitions/Condition" 349 | }, 350 | "minItems": 2, 351 | "maxItems": 10 352 | } 353 | }, 354 | "additionalProperties": false 355 | }, 356 | "FnEquals": { 357 | "type": "object", 358 | "properties": { 359 | "Fn::Equals": { 360 | "description": "https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-conditions.html#intrinsic-function-reference-conditions-equals", 361 | "type": "array", 362 | "items": { 363 | "$ref": "#/definitions/Expression" 364 | }, 365 | "minItems": 2, 366 | "maxItems": 2 367 | } 368 | }, 369 | "additionalProperties": false 370 | }, 371 | "FnIf": { 372 | "type": "object", 373 | "properties": { 374 | "Fn::If": { 375 | "description": "https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-conditions.html#intrinsic-function-reference-conditions-if", 376 | "type": "array", 377 | "items": [ 378 | { 379 | "type": "string" 380 | }, 381 | { 382 | "$ref": "#/definitions/Expression" 383 | }, 384 | { 385 | "$ref": "#/definitions/Expression" 386 | } 387 | ], 388 | "minItems": 3, 389 | "maxItems": 3 390 | } 391 | }, 392 | "additionalProperties": false 393 | }, 394 | "FnNot": { 395 | "type": "object", 396 | "properties": { 397 | "Fn::Not": { 398 | "description": "https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-conditions.html#intrinsic-function-reference-conditions-not", 399 | "type": "array", 400 | "items": [ 401 | { 402 | "$ref": "#/definitions/Condition" 403 | } 404 | ], 405 | "minItems": 1, 406 | "maxItems": 1 407 | } 408 | }, 409 | "additionalProperties": false 410 | }, 411 | "FnOr": { 412 | "type": "object", 413 | "properties": { 414 | "Fn::Or": { 415 | "description": "https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-conditions.html#intrinsic-function-reference-conditions-or", 416 | "type": "array", 417 | "items": { 418 | "$ref": "#/definitions/Condition" 419 | }, 420 | "minItems": 2, 421 | "maxItems": 10 422 | } 423 | }, 424 | "additionalProperties": false 425 | } 426 | } 427 | -------------------------------------------------------------------------------- /src/main/resources/Schema.template: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "{{{draft}}}", 3 | "type": "object", 4 | "definitions": { 5 | "Transform": { 6 | "type": "object", 7 | "oneOf": [ 8 | { 9 | "$comment": "You can use the AWS::Include transform anywhere within the AWS CloudFormation template except in the template parameters section or the template version field. For example, you can use AWS::Include in the mappings section.", 10 | "properties": { 11 | "Name": { 12 | "type": "string", 13 | "enum": [ 14 | "AWS::Include" 15 | ] 16 | }, 17 | "Parameters": { 18 | "type": "object", 19 | "properties": { 20 | "Location": { 21 | "$comment": "The location is an Amazon S3 URI, with a specific file name in an S3 bucket. For example, s3://MyBucketName/MyFile.yaml.", 22 | "type": "string", 23 | "format": "uri" 24 | } 25 | }, 26 | "additionalProperties": false 27 | } 28 | }, 29 | "additionalProperties": false 30 | }, 31 | { 32 | "$comment": "Use a transform to simplify template authoring for serverless applications. ", 33 | "type": "string", 34 | "enum": [ 35 | "AWS::CodeDeployBlueGreen", 36 | "AWS::CodeStar", 37 | "AWS::SecretsManager-2020-07-23", 38 | "AWS::Serverless-2016-10-31" 39 | ] 40 | } 41 | ] 42 | }, 43 | "Attribute": { 44 | "$comment": "Attribute defines the content of a Mapping", 45 | "type": "object", 46 | "patternProperties": { 47 | "^[a-zA-Z0-9._-]{1,255}$": { 48 | "type": [ 49 | "boolean", 50 | "integer", 51 | "number", 52 | "string" 53 | ] 54 | } 55 | }, 56 | "minProperties": 1, 57 | "additionalProperties": false 58 | }, 59 | "Mapping": { 60 | "type": "object", 61 | "patternProperties": { 62 | "^[a-zA-Z0-9._-]{1,255}$": { 63 | "$ref": "#/definitions/Attribute" 64 | } 65 | }, 66 | "minProperties": 1, 67 | "additionalProperties": false 68 | }, 69 | "CommonParams": { 70 | "properties": { 71 | "Description": { 72 | "type": "string", 73 | "maxLength": 4000 74 | }, 75 | "NoEcho": { 76 | "type": "boolean" 77 | }, 78 | "ConstraintDescription": { 79 | "type": "string", 80 | "maxLength": 4000 81 | } 82 | } 83 | }, 84 | "StringParamCommon": { 85 | "allOf": [ 86 | { 87 | "properties": { 88 | "Default": { 89 | "type": "string" 90 | }, 91 | "AllowedValues": { 92 | "type": "array", 93 | "items": { 94 | "type": "string" 95 | }, 96 | "minItems": 1 97 | } 98 | } 99 | }, 100 | { 101 | "$ref": "#/definitions/CommonParams" 102 | } 103 | ] 104 | }, 105 | "StringParam": { 106 | "allOf": [ 107 | { 108 | "type": "object", 109 | "properties": { 110 | "Type": { 111 | "enum": [ 112 | "String" 113 | ] 114 | }, 115 | "AllowedPattern": { 116 | "type": "string" 117 | }, 118 | "MaxLength": { 119 | "type": "integer", 120 | "minimum": 1 121 | }, 122 | "MinLength": { 123 | "type": "integer", 124 | "minimum": 1 125 | } 126 | }, 127 | "required": [ 128 | "Type" 129 | ] 130 | }, 131 | { 132 | "$ref": "#/definitions/StringParamCommon" 133 | } 134 | ] 135 | }, 136 | "StringLikeParam": { 137 | "allOf": [ 138 | { 139 | "type": "object", 140 | "properties": { 141 | "Type": { 142 | "enum": [ 143 | "AWS::EC2::AvailabilityZone::Name", 144 | "AWS::EC2::Image::Id", 145 | "AWS::EC2::Instance::Id", 146 | "AWS::EC2::SecurityGroup::GroupName", 147 | "AWS::EC2::SecurityGroup::Id", 148 | "AWS::EC2::Subnet::Id", 149 | "AWS::EC2::Volume::Id", 150 | "AWS::EC2::VPC::Id", 151 | "AWS::Route53::HostedZone::Id", 152 | "AWS::EC2::KeyPair::KeyName", 153 | "AWS::SSM::Parameter::Value", 154 | "AWS::SSM::Parameter::Value", 155 | "AWS::SSM::Parameter::Value", 156 | "AWS::SSM::Parameter::Value", 157 | "AWS::SSM::Parameter::Value", 158 | "AWS::SSM::Parameter::Value", 159 | "AWS::SSM::Parameter::Value", 160 | "AWS::SSM::Parameter::Value", 161 | "AWS::SSM::Parameter::Value", 162 | "AWS::SSM::Parameter::Value" 163 | ] 164 | } 165 | }, 166 | "required": [ 167 | "Type" 168 | ] 169 | }, 170 | { 171 | "$ref": "#/definitions/StringParamCommon" 172 | } 173 | ] 174 | }, 175 | "NumberParam": { 176 | "allOf": [ 177 | { 178 | "type": "object", 179 | "properties": { 180 | "Type": { 181 | "enum": [ 182 | "Number" 183 | ] 184 | }, 185 | "Default": { 186 | "type": "integer" 187 | }, 188 | "AllowedValues": { 189 | "type": "array", 190 | "items": { 191 | "type": "integer" 192 | }, 193 | "minItems": 1 194 | } 195 | }, 196 | "required": [ 197 | "Type" 198 | ] 199 | }, 200 | { 201 | "$ref": "#/definitions/CommonParams" 202 | } 203 | ] 204 | }, 205 | "CommaDelimitedList": { 206 | "allOf": [ 207 | { 208 | "type": "object", 209 | "properties": { 210 | "Type": { 211 | "enum": [ 212 | "CommaDelimitedList", 213 | "AWS::SSM::Parameter::Value" 214 | ] 215 | }, 216 | "Default": { 217 | "type": "string" 218 | } 219 | }, 220 | "required": [ 221 | "Type" 222 | ] 223 | }, 224 | { 225 | "$ref": "#/definitions/CommonParams" 226 | } 227 | ] 228 | }, 229 | "StringLikeList": { 230 | "allOf": [ 231 | { 232 | "type": "object", 233 | "properties": { 234 | "Type": { 235 | "enum": [ 236 | "List", 237 | "List", 238 | "List", 239 | "List", 240 | "List", 241 | "List", 242 | "List", 243 | "List", 244 | "List", 245 | "AWS::SSM::Parameter::Value>", 246 | "AWS::SSM::Parameter::Value>", 247 | "AWS::SSM::Parameter::Value>", 248 | "AWS::SSM::Parameter::Value>", 249 | "AWS::SSM::Parameter::Value>", 250 | "AWS::SSM::Parameter::Value>", 251 | "AWS::SSM::Parameter::Value>", 252 | "AWS::SSM::Parameter::Value>", 253 | "AWS::SSM::Parameter::Value>", 254 | "AWS::SSM::Parameter::Value>" 255 | ] 256 | }, 257 | "Default": { 258 | "type": "array", 259 | "items": { 260 | "type": "string" 261 | }, 262 | "minItems": 1 263 | } 264 | } 265 | }, 266 | { 267 | "$ref": "#/definitions/CommonParams" 268 | } 269 | ] 270 | }, 271 | "NumberList": { 272 | "allOf": [ 273 | { 274 | "type": "object", 275 | "properties": { 276 | "Type": { 277 | "enum": [ 278 | "List", 279 | "AWS::SSM::Parameter::Value>" 280 | ] 281 | }, 282 | "Default": { 283 | "type": "array", 284 | "items": { 285 | "type": "integer" 286 | }, 287 | "minItems": 1 288 | } 289 | }, 290 | "required": [ 291 | "Type" 292 | ] 293 | }, 294 | { 295 | "$ref": "#/definitions/CommonParams" 296 | } 297 | ] 298 | }, 299 | "parameters": { 300 | "type": "object", 301 | "additionalProperties": { 302 | "oneOf": [ 303 | { 304 | "$ref": "#/definitions/StringParam" 305 | }, 306 | { 307 | "$ref": "#/definitions/StringLikeParam" 308 | }, 309 | { 310 | "$ref": "#/definitions/NumberParam" 311 | }, 312 | { 313 | "$ref": "#/definitions/CommaDelimitedList" 314 | }, 315 | { 316 | "$ref": "#/definitions/StringLikeList" 317 | }, 318 | { 319 | "$ref": "#/definitions/NumberList" 320 | } 321 | ] 322 | } 323 | }, 324 | {{{intrinsics}}} 325 | {{{resources}}} 326 | }, 327 | "additionalProperties": false, 328 | "properties": { 329 | "AWSTemplateFormatVersion": { 330 | "description": "https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/format-version-structure.html", 331 | "type": "string", 332 | "enum": [ 333 | "2010-09-09" 334 | ] 335 | }, 336 | "Description": { 337 | "description": "https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/template-description-structure.html", 338 | "type": "string", 339 | "maxLength": 1024 340 | }, 341 | "Metadata": { 342 | "description": "https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/metadata-section-structure.html", 343 | "type": "object" 344 | }, 345 | "Parameters": { 346 | "description": "https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/parameters-section-structure.html", 347 | "$ref": "#/definitions/parameters" 348 | }, 349 | "Mappings": { 350 | "description": "https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/mappings-section-structure.html", 351 | "type": "object", 352 | "patternProperties": { 353 | "^[a-zA-Z0-9._-]{1,255}$": { 354 | "$ref": "#/definitions/Mapping" 355 | } 356 | }, 357 | "additionalProperties": false 358 | }, 359 | "Conditions": { 360 | "description": "https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/conditions-section-structure.html", 361 | "type": "object" 362 | }, 363 | "Transform": { 364 | "description": "https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/transform-section-structure.html", 365 | "$ref": "#/definitions/Transform" 366 | }, 367 | "Outputs": { 368 | "description": "https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/outputs-section-structure.html", 369 | "type": "object" 370 | }, 371 | "Resources": { 372 | "description": "https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/resources-section-structure.html", 373 | "$ref": "#/definitions/resources" 374 | }, 375 | "Hooks": { 376 | "description": "https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/blue-green.html", 377 | "type": "object" 378 | }, 379 | "Rules": { 380 | "description": "https://docs.aws.amazon.com/servicecatalog/latest/adminguide/reference-template_constraint_rules.html", 381 | "type": "object" 382 | } 383 | }, 384 | "description": "{{description}}", 385 | "required": [ 386 | "Resources" 387 | ] 388 | } 389 | -------------------------------------------------------------------------------- /src/main/resources/config.yml: -------------------------------------------------------------------------------- 1 | settings: 2 | draft: draft07 3 | regions: 4 | - af-south-1 5 | - ap-east-1 6 | - ap-northeast-1 7 | - ap-northeast-2 8 | - ap-northeast-3 9 | - ap-south-1 10 | - ap-southeast-1 11 | - ap-southeast-2 12 | - ca-central-1 13 | - cn-north-1 14 | - cn-northwest-1 15 | - eu-central-1 16 | - eu-north-1 17 | - eu-south-1 18 | - eu-west-1 19 | - eu-west-2 20 | - eu-west-3 21 | - me-south-1 22 | - sa-east-1 23 | - us-east-1 24 | - us-east-2 25 | - us-gov-east-1 26 | - us-gov-west-1 27 | - us-west-1 28 | - us-west-2 29 | output: /tmp/cfn-schemas/ 30 | single: false 31 | intrinsics: true 32 | 33 | # https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-resource-specification.html 34 | specifications: 35 | test: https://cfn-resource-specifications-us-east-1-prod.s3.us-east-1.amazonaws.com/14.1.0/gzip/CloudFormationResourceSpecification.json 36 | af-south-1: https://cfn-resource-specifications-af-south-1-prod.s3.af-south-1.amazonaws.com/latest/gzip/CloudFormationResourceSpecification.json 37 | ap-east-1: https://cfn-resource-specifications-ap-east-1-prod.s3.ap-east-1.amazonaws.com/latest/gzip/CloudFormationResourceSpecification.json 38 | ap-northeast-1: https://d33vqc0rt9ld30.cloudfront.net/latest/gzip/CloudFormationResourceSpecification.json 39 | ap-northeast-2: https://d1ane3fvebulky.cloudfront.net/latest/gzip/CloudFormationResourceSpecification.json 40 | ap-northeast-3: https://d2zq80gdmjim8k.cloudfront.net/latest/gzip/CloudFormationResourceSpecification.json 41 | ap-south-1: https://d2senuesg1djtx.cloudfront.net/latest/gzip/CloudFormationResourceSpecification.json 42 | ap-southeast-1: https://doigdx0kgq9el.cloudfront.net/latest/gzip/CloudFormationResourceSpecification.json 43 | ap-southeast-2: https://d2stg8d246z9di.cloudfront.net/latest/gzip/CloudFormationResourceSpecification.json 44 | ca-central-1: https://d2s8ygphhesbe7.cloudfront.net/latest/gzip/CloudFormationResourceSpecification.json 45 | cn-north-1: https://cfn-resource-specifications-cn-north-1-prod.s3.cn-north-1.amazonaws.com.cn/latest/gzip/CloudFormationResourceSpecification.json 46 | cn-northwest-1: https://cfn-resource-specifications-cn-northwest-1-prod.s3.cn-northwest-1.amazonaws.com.cn/latest/gzip/CloudFormationResourceSpecification.json 47 | eu-central-1: https://d1mta8qj7i28i2.cloudfront.net/latest/gzip/CloudFormationResourceSpecification.json 48 | eu-north-1: https://diy8iv58sj6ba.cloudfront.net/latest/gzip/CloudFormationResourceSpecification.json 49 | eu-south-1: https://cfn-resource-specifications-eu-south-1-prod.s3.eu-south-1.amazonaws.com/latest/gzip/CloudFormationResourceSpecification.json 50 | eu-west-1: https://d3teyb21fexa9r.cloudfront.net/latest/gzip/CloudFormationResourceSpecification.json 51 | eu-west-2: https://d1742qcu2c1ncx.cloudfront.net/latest/gzip/CloudFormationResourceSpecification.json 52 | eu-west-3: https://d2d0mfegowb3wk.cloudfront.net/latest/gzip/CloudFormationResourceSpecification.json 53 | me-south-1: https://cfn-resource-specifications-me-south-1-prod.s3.me-south-1.amazonaws.com/latest/gzip/CloudFormationResourceSpecification.json 54 | sa-east-1: https://d3c9jyj3w509b0.cloudfront.net/latest/gzip/CloudFormationResourceSpecification.json 55 | us-east-1: https://d1uauaxba7bl26.cloudfront.net/latest/gzip/CloudFormationResourceSpecification.json 56 | us-east-2: https://dnwj8swjjbsbt.cloudfront.net/latest/gzip/CloudFormationResourceSpecification.json 57 | us-gov-east-1: https://s3.us-gov-east-1.amazonaws.com/cfn-resource-specifications-us-gov-east-1-prod/latest/gzip/CloudFormationResourceSpecification.json 58 | us-gov-west-1: https://s3.us-gov-west-1.amazonaws.com/cfn-resource-specifications-us-gov-west-1-prod/latest/gzip/CloudFormationResourceSpecification.json 59 | us-west-1: https://d68hl49wbnanq.cloudfront.net/latest/gzip/CloudFormationResourceSpecification.json 60 | us-west-2: https://d201a2mn26r7lk.cloudfront.net/latest/gzip/CloudFormationResourceSpecification.json 61 | 62 | groups: 63 | default: 64 | includes: 65 | - Tag 66 | 67 | networking: 68 | includes: 69 | - AWS::EC2.* 70 | excludes: 71 | - AWS::EC2::(Spot|Launch|Instance|Volume|Host).* 72 | 73 | serverless: 74 | includes: 75 | - AWS::ApiGateway.* 76 | - AWS::Lambda.* 77 | - AWS::IAM.* 78 | 79 | 3tierAsgApp: 80 | includes: 81 | - AWS::ElasticLoadBalancingV2.* 82 | - AWS::RDS.* 83 | - AWS::AutoScal.* 84 | - AWS::IAM.* 85 | 86 | all: 87 | includes: 88 | - AWS.* 89 | - Alexa.* 90 | -------------------------------------------------------------------------------- /src/test/java/aws/cfn/codegen/GroupSpecTest.java: -------------------------------------------------------------------------------- 1 | package aws.cfn.codegen; 2 | 3 | import aws.cfn.codegen.json.GroupSpec; 4 | import com.google.common.collect.Sets; 5 | import org.junit.Test; 6 | 7 | import static org.junit.Assert.*; 8 | 9 | import java.io.IOException; 10 | import java.nio.file.Files; 11 | import java.nio.file.Paths; 12 | import java.util.List; 13 | import java.util.regex.Pattern; 14 | import java.util.stream.Collectors; 15 | 16 | public class GroupSpecTest { 17 | 18 | private final List resources; 19 | 20 | public GroupSpecTest() throws IOException { 21 | resources = Files.readAllLines( 22 | Paths.get("src/test/java/aws/cfn/codegen/resources.txt")); 23 | } 24 | 25 | @Test 26 | public void testPatterns() { 27 | Pattern pattern = Pattern.compile("AWS::EC2.*"); 28 | assertTrue(pattern.matcher("AWS::EC2::VPC").matches()); 29 | 30 | pattern = Pattern.compile("AWS::EC2::Host"); 31 | assertFalse(pattern.matcher("AWS::EC2::VPC").matches()); 32 | assertTrue(pattern.matcher("AWS::EC2::Host").matches()); 33 | 34 | String source = "AWS::EC2::(Spot|Launch|Instance|Volume|Host).*"; 35 | pattern = Pattern.compile(source); 36 | assertTrue(pattern.matcher("AWS::EC2::LaunchTemplate").matches()); 37 | } 38 | 39 | 40 | @Test 41 | public void testSpec() throws IOException { 42 | GroupSpec spec = GroupSpec.includesOnly("ec2","AWS::EC2.*"); 43 | spec.compile(); 44 | List ec2 = resources.stream() 45 | .filter(spec::isIncluded) 46 | .collect(Collectors.toList()); 47 | assertEquals(95, ec2.size()); 48 | } 49 | 50 | @Test 51 | public void testSpecNetworking() throws IOException { 52 | GroupSpec spec = new GroupSpec(); 53 | spec.setIncludes(Sets.newHashSet("AWS::EC2.*")); 54 | spec.setExcludes(Sets.newHashSet("AWS::EC2::(Spot|Launch|Instance|Volume|Host).*")); 55 | spec.setGroupName("networking"); 56 | spec.compile(); 57 | List networking = resources.stream() 58 | .filter(spec::isIncluded) 59 | .collect(Collectors.toList()); 60 | assertEquals(43, networking.size()); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/test/java/aws/cfn/codegen/MainTest.java: -------------------------------------------------------------------------------- 1 | package aws.cfn.codegen; 2 | 3 | 4 | import aws.cfn.codegen.json.Main; 5 | import org.junit.Test; 6 | 7 | /** 8 | * Can't be run as part of CI/CD due to filesystem dependency. 9 | */ 10 | public class MainTest { 11 | // @Test 12 | public void codegen() throws Exception { 13 | Main.main( 14 | new String[] { 15 | "--aws-region", 16 | "us-east-2", 17 | "--output-dir", 18 | "/tmp/cfn-v2/json/", 19 | "--json-schema-version", 20 | "draft04" 21 | } 22 | ); 23 | } 24 | 25 | // @Test 26 | public void codegenConfigSpec() throws Exception { 27 | Main.main( 28 | new String[] { 29 | "--cfn-spec-url", 30 | "https://dnwj8swjjbsbt.cloudfront.net/latest/gzip/CloudFormationResourceSpecification.json", 31 | "--aws-region", 32 | "us-east-2", 33 | "--output-dir", 34 | "/tmp/cfn-v2/cfg-json/", 35 | "--config-file", 36 | "src/main/resources/config.yml" 37 | } 38 | ); 39 | } 40 | 41 | // @Test 42 | public void codegenDefault() throws Exception { 43 | Main.main(new String[0]); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/test/java/aws/cfn/codegen/resources.txt: -------------------------------------------------------------------------------- 1 | AWS::AmazonMQ::Broker 2 | AWS::AmazonMQ::Broker.ConfigurationId 3 | AWS::AmazonMQ::Broker.LogList 4 | AWS::AmazonMQ::Broker.MaintenanceWindow 5 | AWS::AmazonMQ::Broker.User 6 | AWS::AmazonMQ::Configuration 7 | AWS::ApiGateway::Account 8 | AWS::ApiGateway::ApiKey 9 | AWS::ApiGateway::ApiKey.StageKey 10 | AWS::ApiGateway::Authorizer 11 | AWS::ApiGateway::BasePathMapping 12 | AWS::ApiGateway::ClientCertificate 13 | AWS::ApiGateway::Deployment 14 | AWS::ApiGateway::Deployment.AccessLogSetting 15 | AWS::ApiGateway::Deployment.CanarySetting 16 | AWS::ApiGateway::Deployment.DeploymentCanarySettings 17 | AWS::ApiGateway::Deployment.MethodSetting 18 | AWS::ApiGateway::Deployment.StageDescription 19 | AWS::ApiGateway::DocumentationPart 20 | AWS::ApiGateway::DocumentationPart.Location 21 | AWS::ApiGateway::DocumentationVersion 22 | AWS::ApiGateway::DomainName 23 | AWS::ApiGateway::DomainName.EndpointConfiguration 24 | AWS::ApiGateway::GatewayResponse 25 | AWS::ApiGateway::Method 26 | AWS::ApiGateway::Method.Integration 27 | AWS::ApiGateway::Method.IntegrationResponse 28 | AWS::ApiGateway::Method.MethodResponse 29 | AWS::ApiGateway::Model 30 | AWS::ApiGateway::RequestValidator 31 | AWS::ApiGateway::Resource 32 | AWS::ApiGateway::RestApi 33 | AWS::ApiGateway::RestApi.EndpointConfiguration 34 | AWS::ApiGateway::RestApi.S3Location 35 | AWS::ApiGateway::Stage 36 | AWS::ApiGateway::Stage.AccessLogSetting 37 | AWS::ApiGateway::Stage.CanarySetting 38 | AWS::ApiGateway::Stage.MethodSetting 39 | AWS::ApiGateway::UsagePlan 40 | AWS::ApiGateway::UsagePlan.ApiStage 41 | AWS::ApiGateway::UsagePlan.QuotaSettings 42 | AWS::ApiGateway::UsagePlan.ThrottleSettings 43 | AWS::ApiGateway::UsagePlanKey 44 | AWS::ApiGateway::VpcLink 45 | AWS::AppSync::ApiKey 46 | AWS::AppSync::DataSource 47 | AWS::AppSync::DataSource.DynamoDBConfig 48 | AWS::AppSync::DataSource.ElasticsearchConfig 49 | AWS::AppSync::DataSource.HttpConfig 50 | AWS::AppSync::DataSource.LambdaConfig 51 | AWS::AppSync::GraphQLApi 52 | AWS::AppSync::GraphQLApi.LogConfig 53 | AWS::AppSync::GraphQLApi.OpenIDConnectConfig 54 | AWS::AppSync::GraphQLApi.UserPoolConfig 55 | AWS::AppSync::GraphQLSchema 56 | AWS::AppSync::Resolver 57 | AWS::ApplicationAutoScaling::ScalableTarget 58 | AWS::ApplicationAutoScaling::ScalableTarget.ScalableTargetAction 59 | AWS::ApplicationAutoScaling::ScalableTarget.ScheduledAction 60 | AWS::ApplicationAutoScaling::ScalingPolicy 61 | AWS::ApplicationAutoScaling::ScalingPolicy.CustomizedMetricSpecification 62 | AWS::ApplicationAutoScaling::ScalingPolicy.MetricDimension 63 | AWS::ApplicationAutoScaling::ScalingPolicy.PredefinedMetricSpecification 64 | AWS::ApplicationAutoScaling::ScalingPolicy.StepAdjustment 65 | AWS::ApplicationAutoScaling::ScalingPolicy.StepScalingPolicyConfiguration 66 | AWS::ApplicationAutoScaling::ScalingPolicy.TargetTrackingScalingPolicyConfiguration 67 | AWS::Athena::NamedQuery 68 | AWS::AutoScaling::AutoScalingGroup 69 | AWS::AutoScaling::AutoScalingGroup.LaunchTemplateSpecification 70 | AWS::AutoScaling::AutoScalingGroup.LifecycleHookSpecification 71 | AWS::AutoScaling::AutoScalingGroup.MetricsCollection 72 | AWS::AutoScaling::AutoScalingGroup.NotificationConfiguration 73 | AWS::AutoScaling::AutoScalingGroup.TagProperty 74 | AWS::AutoScaling::LaunchConfiguration 75 | AWS::AutoScaling::LaunchConfiguration.BlockDevice 76 | AWS::AutoScaling::LaunchConfiguration.BlockDeviceMapping 77 | AWS::AutoScaling::LifecycleHook 78 | AWS::AutoScaling::ScalingPolicy 79 | AWS::AutoScaling::ScalingPolicy.CustomizedMetricSpecification 80 | AWS::AutoScaling::ScalingPolicy.MetricDimension 81 | AWS::AutoScaling::ScalingPolicy.PredefinedMetricSpecification 82 | AWS::AutoScaling::ScalingPolicy.StepAdjustment 83 | AWS::AutoScaling::ScalingPolicy.TargetTrackingConfiguration 84 | AWS::AutoScaling::ScheduledAction 85 | AWS::AutoScalingPlans::ScalingPlan 86 | AWS::AutoScalingPlans::ScalingPlan.ApplicationSource 87 | AWS::AutoScalingPlans::ScalingPlan.CustomizedScalingMetricSpecification 88 | AWS::AutoScalingPlans::ScalingPlan.MetricDimension 89 | AWS::AutoScalingPlans::ScalingPlan.PredefinedScalingMetricSpecification 90 | AWS::AutoScalingPlans::ScalingPlan.ScalingInstruction 91 | AWS::AutoScalingPlans::ScalingPlan.TagFilter 92 | AWS::AutoScalingPlans::ScalingPlan.TargetTrackingConfiguration 93 | AWS::Batch::ComputeEnvironment 94 | AWS::Batch::ComputeEnvironment.ComputeResources 95 | AWS::Batch::JobDefinition 96 | AWS::Batch::JobDefinition.ContainerProperties 97 | AWS::Batch::JobDefinition.Environment 98 | AWS::Batch::JobDefinition.MountPoints 99 | AWS::Batch::JobDefinition.RetryStrategy 100 | AWS::Batch::JobDefinition.Timeout 101 | AWS::Batch::JobDefinition.Ulimit 102 | AWS::Batch::JobDefinition.Volumes 103 | AWS::Batch::JobDefinition.VolumesHost 104 | AWS::Batch::JobQueue 105 | AWS::Batch::JobQueue.ComputeEnvironmentOrder 106 | AWS::Budgets::Budget 107 | AWS::Budgets::Budget.BudgetData 108 | AWS::Budgets::Budget.CostTypes 109 | AWS::Budgets::Budget.Notification 110 | AWS::Budgets::Budget.NotificationWithSubscribers 111 | AWS::Budgets::Budget.Spend 112 | AWS::Budgets::Budget.Subscriber 113 | AWS::Budgets::Budget.TimePeriod 114 | AWS::CertificateManager::Certificate 115 | AWS::CertificateManager::Certificate.DomainValidationOption 116 | AWS::Cloud9::EnvironmentEC2 117 | AWS::Cloud9::EnvironmentEC2.Repository 118 | AWS::CloudFormation::CustomResource 119 | AWS::CloudFormation::Stack 120 | AWS::CloudFormation::WaitCondition 121 | AWS::CloudFormation::WaitConditionHandle 122 | AWS::CloudFront::CloudFrontOriginAccessIdentity 123 | AWS::CloudFront::CloudFrontOriginAccessIdentity.CloudFrontOriginAccessIdentityConfig 124 | AWS::CloudFront::Distribution 125 | AWS::CloudFront::Distribution.CacheBehavior 126 | AWS::CloudFront::Distribution.Cookies 127 | AWS::CloudFront::Distribution.CustomErrorResponse 128 | AWS::CloudFront::Distribution.CustomOriginConfig 129 | AWS::CloudFront::Distribution.DefaultCacheBehavior 130 | AWS::CloudFront::Distribution.DistributionConfig 131 | AWS::CloudFront::Distribution.ForwardedValues 132 | AWS::CloudFront::Distribution.GeoRestriction 133 | AWS::CloudFront::Distribution.LambdaFunctionAssociation 134 | AWS::CloudFront::Distribution.Logging 135 | AWS::CloudFront::Distribution.Origin 136 | AWS::CloudFront::Distribution.OriginCustomHeader 137 | AWS::CloudFront::Distribution.Restrictions 138 | AWS::CloudFront::Distribution.S3OriginConfig 139 | AWS::CloudFront::Distribution.ViewerCertificate 140 | AWS::CloudFront::StreamingDistribution 141 | AWS::CloudFront::StreamingDistribution.Logging 142 | AWS::CloudFront::StreamingDistribution.S3Origin 143 | AWS::CloudFront::StreamingDistribution.StreamingDistributionConfig 144 | AWS::CloudFront::StreamingDistribution.TrustedSigners 145 | AWS::CloudTrail::Trail 146 | AWS::CloudTrail::Trail.DataResource 147 | AWS::CloudTrail::Trail.EventSelector 148 | AWS::CloudWatch::Alarm 149 | AWS::CloudWatch::Alarm.Dimension 150 | AWS::CloudWatch::Dashboard 151 | AWS::CodeBuild::Project 152 | AWS::CodeBuild::Project.Artifacts 153 | AWS::CodeBuild::Project.CloudWatchLogsConfig 154 | AWS::CodeBuild::Project.Environment 155 | AWS::CodeBuild::Project.EnvironmentVariable 156 | AWS::CodeBuild::Project.LogsConfig 157 | AWS::CodeBuild::Project.ProjectCache 158 | AWS::CodeBuild::Project.ProjectTriggers 159 | AWS::CodeBuild::Project.S3LogsConfig 160 | AWS::CodeBuild::Project.Source 161 | AWS::CodeBuild::Project.SourceAuth 162 | AWS::CodeBuild::Project.VpcConfig 163 | AWS::CodeCommit::Repository 164 | AWS::CodeCommit::Repository.RepositoryTrigger 165 | AWS::CodeDeploy::Application 166 | AWS::CodeDeploy::DeploymentConfig 167 | AWS::CodeDeploy::DeploymentConfig.MinimumHealthyHosts 168 | AWS::CodeDeploy::DeploymentGroup 169 | AWS::CodeDeploy::DeploymentGroup.Alarm 170 | AWS::CodeDeploy::DeploymentGroup.AlarmConfiguration 171 | AWS::CodeDeploy::DeploymentGroup.AutoRollbackConfiguration 172 | AWS::CodeDeploy::DeploymentGroup.Deployment 173 | AWS::CodeDeploy::DeploymentGroup.DeploymentStyle 174 | AWS::CodeDeploy::DeploymentGroup.EC2TagFilter 175 | AWS::CodeDeploy::DeploymentGroup.EC2TagSet 176 | AWS::CodeDeploy::DeploymentGroup.EC2TagSetListObject 177 | AWS::CodeDeploy::DeploymentGroup.ELBInfo 178 | AWS::CodeDeploy::DeploymentGroup.GitHubLocation 179 | AWS::CodeDeploy::DeploymentGroup.LoadBalancerInfo 180 | AWS::CodeDeploy::DeploymentGroup.OnPremisesTagSet 181 | AWS::CodeDeploy::DeploymentGroup.OnPremisesTagSetListObject 182 | AWS::CodeDeploy::DeploymentGroup.RevisionLocation 183 | AWS::CodeDeploy::DeploymentGroup.S3Location 184 | AWS::CodeDeploy::DeploymentGroup.TagFilter 185 | AWS::CodeDeploy::DeploymentGroup.TargetGroupInfo 186 | AWS::CodeDeploy::DeploymentGroup.TriggerConfig 187 | AWS::CodePipeline::CustomActionType 188 | AWS::CodePipeline::CustomActionType.ArtifactDetails 189 | AWS::CodePipeline::CustomActionType.ConfigurationProperties 190 | AWS::CodePipeline::CustomActionType.Settings 191 | AWS::CodePipeline::Pipeline 192 | AWS::CodePipeline::Pipeline.ActionDeclaration 193 | AWS::CodePipeline::Pipeline.ActionTypeId 194 | AWS::CodePipeline::Pipeline.ArtifactStore 195 | AWS::CodePipeline::Pipeline.BlockerDeclaration 196 | AWS::CodePipeline::Pipeline.EncryptionKey 197 | AWS::CodePipeline::Pipeline.InputArtifact 198 | AWS::CodePipeline::Pipeline.OutputArtifact 199 | AWS::CodePipeline::Pipeline.StageDeclaration 200 | AWS::CodePipeline::Pipeline.StageTransition 201 | AWS::CodePipeline::Webhook 202 | AWS::CodePipeline::Webhook.WebhookAuthConfiguration 203 | AWS::CodePipeline::Webhook.WebhookFilterRule 204 | AWS::Cognito::IdentityPool 205 | AWS::Cognito::IdentityPool.CognitoIdentityProvider 206 | AWS::Cognito::IdentityPool.CognitoStreams 207 | AWS::Cognito::IdentityPool.PushSync 208 | AWS::Cognito::IdentityPoolRoleAttachment 209 | AWS::Cognito::IdentityPoolRoleAttachment.MappingRule 210 | AWS::Cognito::IdentityPoolRoleAttachment.RoleMapping 211 | AWS::Cognito::IdentityPoolRoleAttachment.RulesConfigurationType 212 | AWS::Cognito::UserPool 213 | AWS::Cognito::UserPool.AdminCreateUserConfig 214 | AWS::Cognito::UserPool.DeviceConfiguration 215 | AWS::Cognito::UserPool.EmailConfiguration 216 | AWS::Cognito::UserPool.InviteMessageTemplate 217 | AWS::Cognito::UserPool.LambdaConfig 218 | AWS::Cognito::UserPool.NumberAttributeConstraints 219 | AWS::Cognito::UserPool.PasswordPolicy 220 | AWS::Cognito::UserPool.Policies 221 | AWS::Cognito::UserPool.SchemaAttribute 222 | AWS::Cognito::UserPool.SmsConfiguration 223 | AWS::Cognito::UserPool.StringAttributeConstraints 224 | AWS::Cognito::UserPoolClient 225 | AWS::Cognito::UserPoolGroup 226 | AWS::Cognito::UserPoolUser 227 | AWS::Cognito::UserPoolUser.AttributeType 228 | AWS::Cognito::UserPoolUserToGroupAttachment 229 | AWS::Config::AggregationAuthorization 230 | AWS::Config::ConfigRule 231 | AWS::Config::ConfigRule.Scope 232 | AWS::Config::ConfigRule.Source 233 | AWS::Config::ConfigRule.SourceDetail 234 | AWS::Config::ConfigurationAggregator 235 | AWS::Config::ConfigurationAggregator.AccountAggregationSource 236 | AWS::Config::ConfigurationAggregator.OrganizationAggregationSource 237 | AWS::Config::ConfigurationRecorder 238 | AWS::Config::ConfigurationRecorder.RecordingGroup 239 | AWS::Config::DeliveryChannel 240 | AWS::Config::DeliveryChannel.ConfigSnapshotDeliveryProperties 241 | AWS::DAX::Cluster 242 | AWS::DAX::Cluster.SSESpecification 243 | AWS::DAX::ParameterGroup 244 | AWS::DAX::SubnetGroup 245 | AWS::DMS::Certificate 246 | AWS::DMS::Endpoint 247 | AWS::DMS::Endpoint.DynamoDbSettings 248 | AWS::DMS::Endpoint.MongoDbSettings 249 | AWS::DMS::Endpoint.S3Settings 250 | AWS::DMS::EventSubscription 251 | AWS::DMS::ReplicationInstance 252 | AWS::DMS::ReplicationSubnetGroup 253 | AWS::DMS::ReplicationTask 254 | AWS::DataPipeline::Pipeline 255 | AWS::DataPipeline::Pipeline.Field 256 | AWS::DataPipeline::Pipeline.ParameterAttribute 257 | AWS::DataPipeline::Pipeline.ParameterObject 258 | AWS::DataPipeline::Pipeline.ParameterValue 259 | AWS::DataPipeline::Pipeline.PipelineObject 260 | AWS::DataPipeline::Pipeline.PipelineTag 261 | AWS::DirectoryService::MicrosoftAD 262 | AWS::DirectoryService::MicrosoftAD.VpcSettings 263 | AWS::DirectoryService::SimpleAD 264 | AWS::DirectoryService::SimpleAD.VpcSettings 265 | AWS::DynamoDB::Table 266 | AWS::DynamoDB::Table.AttributeDefinition 267 | AWS::DynamoDB::Table.GlobalSecondaryIndex 268 | AWS::DynamoDB::Table.KeySchema 269 | AWS::DynamoDB::Table.LocalSecondaryIndex 270 | AWS::DynamoDB::Table.PointInTimeRecoverySpecification 271 | AWS::DynamoDB::Table.Projection 272 | AWS::DynamoDB::Table.ProvisionedThroughput 273 | AWS::DynamoDB::Table.SSESpecification 274 | AWS::DynamoDB::Table.StreamSpecification 275 | AWS::DynamoDB::Table.TimeToLiveSpecification 276 | AWS::EC2::CustomerGateway 277 | AWS::EC2::DHCPOptions 278 | AWS::EC2::EIP 279 | AWS::EC2::EIPAssociation 280 | AWS::EC2::EgressOnlyInternetGateway 281 | AWS::EC2::FlowLog 282 | AWS::EC2::Host 283 | AWS::EC2::Instance 284 | AWS::EC2::Instance.AssociationParameter 285 | AWS::EC2::Instance.BlockDeviceMapping 286 | AWS::EC2::Instance.CreditSpecification 287 | AWS::EC2::Instance.Ebs 288 | AWS::EC2::Instance.ElasticGpuSpecification 289 | AWS::EC2::Instance.InstanceIpv6Address 290 | AWS::EC2::Instance.LaunchTemplateSpecification 291 | AWS::EC2::Instance.NetworkInterface 292 | AWS::EC2::Instance.NoDevice 293 | AWS::EC2::Instance.PrivateIpAddressSpecification 294 | AWS::EC2::Instance.SsmAssociation 295 | AWS::EC2::Instance.Volume 296 | AWS::EC2::InternetGateway 297 | AWS::EC2::LaunchTemplate 298 | AWS::EC2::LaunchTemplate.BlockDeviceMapping 299 | AWS::EC2::LaunchTemplate.CreditSpecification 300 | AWS::EC2::LaunchTemplate.Ebs 301 | AWS::EC2::LaunchTemplate.ElasticGpuSpecification 302 | AWS::EC2::LaunchTemplate.IamInstanceProfile 303 | AWS::EC2::LaunchTemplate.InstanceMarketOptions 304 | AWS::EC2::LaunchTemplate.Ipv6Add 305 | AWS::EC2::LaunchTemplate.LaunchTemplateData 306 | AWS::EC2::LaunchTemplate.Monitoring 307 | AWS::EC2::LaunchTemplate.NetworkInterface 308 | AWS::EC2::LaunchTemplate.Placement 309 | AWS::EC2::LaunchTemplate.PrivateIpAdd 310 | AWS::EC2::LaunchTemplate.SpotOptions 311 | AWS::EC2::LaunchTemplate.TagSpecification 312 | AWS::EC2::NatGateway 313 | AWS::EC2::NetworkAcl 314 | AWS::EC2::NetworkAclEntry 315 | AWS::EC2::NetworkAclEntry.Icmp 316 | AWS::EC2::NetworkAclEntry.PortRange 317 | AWS::EC2::NetworkInterface 318 | AWS::EC2::NetworkInterface.InstanceIpv6Address 319 | AWS::EC2::NetworkInterface.PrivateIpAddressSpecification 320 | AWS::EC2::NetworkInterfaceAttachment 321 | AWS::EC2::NetworkInterfacePermission 322 | AWS::EC2::PlacementGroup 323 | AWS::EC2::Route 324 | AWS::EC2::RouteTable 325 | AWS::EC2::SecurityGroup 326 | AWS::EC2::SecurityGroup.Egress 327 | AWS::EC2::SecurityGroup.Ingress 328 | AWS::EC2::SecurityGroupEgress 329 | AWS::EC2::SecurityGroupIngress 330 | AWS::EC2::SpotFleet 331 | AWS::EC2::SpotFleet.BlockDeviceMapping 332 | AWS::EC2::SpotFleet.ClassicLoadBalancer 333 | AWS::EC2::SpotFleet.ClassicLoadBalancersConfig 334 | AWS::EC2::SpotFleet.EbsBlockDevice 335 | AWS::EC2::SpotFleet.FleetLaunchTemplateSpecification 336 | AWS::EC2::SpotFleet.GroupIdentifier 337 | AWS::EC2::SpotFleet.IamInstanceProfileSpecification 338 | AWS::EC2::SpotFleet.InstanceIpv6Address 339 | AWS::EC2::SpotFleet.InstanceNetworkInterfaceSpecification 340 | AWS::EC2::SpotFleet.LaunchTemplateConfig 341 | AWS::EC2::SpotFleet.LaunchTemplateOverrides 342 | AWS::EC2::SpotFleet.LoadBalancersConfig 343 | AWS::EC2::SpotFleet.PrivateIpAddressSpecification 344 | AWS::EC2::SpotFleet.SpotFleetLaunchSpecification 345 | AWS::EC2::SpotFleet.SpotFleetMonitoring 346 | AWS::EC2::SpotFleet.SpotFleetRequestConfigData 347 | AWS::EC2::SpotFleet.SpotFleetTagSpecification 348 | AWS::EC2::SpotFleet.SpotPlacement 349 | AWS::EC2::SpotFleet.TargetGroup 350 | AWS::EC2::SpotFleet.TargetGroupsConfig 351 | AWS::EC2::Subnet 352 | AWS::EC2::SubnetCidrBlock 353 | AWS::EC2::SubnetNetworkAclAssociation 354 | AWS::EC2::SubnetRouteTableAssociation 355 | AWS::EC2::TrunkInterfaceAssociation 356 | AWS::EC2::VPC 357 | AWS::EC2::VPCCidrBlock 358 | AWS::EC2::VPCDHCPOptionsAssociation 359 | AWS::EC2::VPCEndpoint 360 | AWS::EC2::VPCEndpointConnectionNotification 361 | AWS::EC2::VPCEndpointServicePermissions 362 | AWS::EC2::VPCGatewayAttachment 363 | AWS::EC2::VPCPeeringConnection 364 | AWS::EC2::VPNConnection 365 | AWS::EC2::VPNConnection.VpnTunnelOptionsSpecification 366 | AWS::EC2::VPNConnectionRoute 367 | AWS::EC2::VPNGateway 368 | AWS::EC2::VPNGatewayRoutePropagation 369 | AWS::EC2::Volume 370 | AWS::EC2::VolumeAttachment 371 | AWS::ECR::Repository 372 | AWS::ECR::Repository.LifecyclePolicy 373 | AWS::ECS::Cluster 374 | AWS::ECS::Service 375 | AWS::ECS::Service.AwsVpcConfiguration 376 | AWS::ECS::Service.DeploymentConfiguration 377 | AWS::ECS::Service.LoadBalancer 378 | AWS::ECS::Service.NetworkConfiguration 379 | AWS::ECS::Service.PlacementConstraint 380 | AWS::ECS::Service.PlacementStrategy 381 | AWS::ECS::Service.ServiceRegistry 382 | AWS::ECS::TaskDefinition 383 | AWS::ECS::TaskDefinition.ContainerDefinition 384 | AWS::ECS::TaskDefinition.Device 385 | AWS::ECS::TaskDefinition.DockerVolumeConfiguration 386 | AWS::ECS::TaskDefinition.HealthCheck 387 | AWS::ECS::TaskDefinition.HostEntry 388 | AWS::ECS::TaskDefinition.HostVolumeProperties 389 | AWS::ECS::TaskDefinition.KernelCapabilities 390 | AWS::ECS::TaskDefinition.KeyValuePair 391 | AWS::ECS::TaskDefinition.LinuxParameters 392 | AWS::ECS::TaskDefinition.LogConfiguration 393 | AWS::ECS::TaskDefinition.MountPoint 394 | AWS::ECS::TaskDefinition.PortMapping 395 | AWS::ECS::TaskDefinition.RepositoryCredentials 396 | AWS::ECS::TaskDefinition.TaskDefinitionPlacementConstraint 397 | AWS::ECS::TaskDefinition.Tmpfs 398 | AWS::ECS::TaskDefinition.Ulimit 399 | AWS::ECS::TaskDefinition.Volume 400 | AWS::ECS::TaskDefinition.VolumeFrom 401 | AWS::EFS::FileSystem 402 | AWS::EFS::FileSystem.ElasticFileSystemTag 403 | AWS::EFS::MountTarget 404 | AWS::EKS::Cluster 405 | AWS::EKS::Cluster.ResourcesVpcConfig 406 | AWS::EMR::Cluster 407 | AWS::EMR::Cluster.Application 408 | AWS::EMR::Cluster.AutoScalingPolicy 409 | AWS::EMR::Cluster.BootstrapActionConfig 410 | AWS::EMR::Cluster.CloudWatchAlarmDefinition 411 | AWS::EMR::Cluster.Configuration 412 | AWS::EMR::Cluster.EbsBlockDeviceConfig 413 | AWS::EMR::Cluster.EbsConfiguration 414 | AWS::EMR::Cluster.InstanceFleetConfig 415 | AWS::EMR::Cluster.InstanceFleetProvisioningSpecifications 416 | AWS::EMR::Cluster.InstanceGroupConfig 417 | AWS::EMR::Cluster.InstanceTypeConfig 418 | AWS::EMR::Cluster.JobFlowInstancesConfig 419 | AWS::EMR::Cluster.KerberosAttributes 420 | AWS::EMR::Cluster.MetricDimension 421 | AWS::EMR::Cluster.PlacementType 422 | AWS::EMR::Cluster.ScalingAction 423 | AWS::EMR::Cluster.ScalingConstraints 424 | AWS::EMR::Cluster.ScalingRule 425 | AWS::EMR::Cluster.ScalingTrigger 426 | AWS::EMR::Cluster.ScriptBootstrapActionConfig 427 | AWS::EMR::Cluster.SimpleScalingPolicyConfiguration 428 | AWS::EMR::Cluster.SpotProvisioningSpecification 429 | AWS::EMR::Cluster.VolumeSpecification 430 | AWS::EMR::InstanceFleetConfig 431 | AWS::EMR::InstanceFleetConfig.Configuration 432 | AWS::EMR::InstanceFleetConfig.EbsBlockDeviceConfig 433 | AWS::EMR::InstanceFleetConfig.EbsConfiguration 434 | AWS::EMR::InstanceFleetConfig.InstanceFleetProvisioningSpecifications 435 | AWS::EMR::InstanceFleetConfig.InstanceTypeConfig 436 | AWS::EMR::InstanceFleetConfig.SpotProvisioningSpecification 437 | AWS::EMR::InstanceFleetConfig.VolumeSpecification 438 | AWS::EMR::InstanceGroupConfig 439 | AWS::EMR::InstanceGroupConfig.AutoScalingPolicy 440 | AWS::EMR::InstanceGroupConfig.CloudWatchAlarmDefinition 441 | AWS::EMR::InstanceGroupConfig.Configuration 442 | AWS::EMR::InstanceGroupConfig.EbsBlockDeviceConfig 443 | AWS::EMR::InstanceGroupConfig.EbsConfiguration 444 | AWS::EMR::InstanceGroupConfig.MetricDimension 445 | AWS::EMR::InstanceGroupConfig.ScalingAction 446 | AWS::EMR::InstanceGroupConfig.ScalingConstraints 447 | AWS::EMR::InstanceGroupConfig.ScalingRule 448 | AWS::EMR::InstanceGroupConfig.ScalingTrigger 449 | AWS::EMR::InstanceGroupConfig.SimpleScalingPolicyConfiguration 450 | AWS::EMR::InstanceGroupConfig.VolumeSpecification 451 | AWS::EMR::SecurityConfiguration 452 | AWS::EMR::Step 453 | AWS::EMR::Step.HadoopJarStepConfig 454 | AWS::EMR::Step.KeyValue 455 | AWS::ElastiCache::CacheCluster 456 | AWS::ElastiCache::ParameterGroup 457 | AWS::ElastiCache::ReplicationGroup 458 | AWS::ElastiCache::ReplicationGroup.NodeGroupConfiguration 459 | AWS::ElastiCache::SecurityGroup 460 | AWS::ElastiCache::SecurityGroupIngress 461 | AWS::ElastiCache::SubnetGroup 462 | AWS::ElasticBeanstalk::Application 463 | AWS::ElasticBeanstalk::Application.ApplicationResourceLifecycleConfig 464 | AWS::ElasticBeanstalk::Application.ApplicationVersionLifecycleConfig 465 | AWS::ElasticBeanstalk::Application.MaxAgeRule 466 | AWS::ElasticBeanstalk::Application.MaxCountRule 467 | AWS::ElasticBeanstalk::ApplicationVersion 468 | AWS::ElasticBeanstalk::ApplicationVersion.SourceBundle 469 | AWS::ElasticBeanstalk::ConfigurationTemplate 470 | AWS::ElasticBeanstalk::ConfigurationTemplate.ConfigurationOptionSetting 471 | AWS::ElasticBeanstalk::ConfigurationTemplate.SourceConfiguration 472 | AWS::ElasticBeanstalk::Environment 473 | AWS::ElasticBeanstalk::Environment.OptionSetting 474 | AWS::ElasticBeanstalk::Environment.Tier 475 | AWS::ElasticLoadBalancing::LoadBalancer 476 | AWS::ElasticLoadBalancing::LoadBalancer.AccessLoggingPolicy 477 | AWS::ElasticLoadBalancing::LoadBalancer.AppCookieStickinessPolicy 478 | AWS::ElasticLoadBalancing::LoadBalancer.ConnectionDrainingPolicy 479 | AWS::ElasticLoadBalancing::LoadBalancer.ConnectionSettings 480 | AWS::ElasticLoadBalancing::LoadBalancer.HealthCheck 481 | AWS::ElasticLoadBalancing::LoadBalancer.LBCookieStickinessPolicy 482 | AWS::ElasticLoadBalancing::LoadBalancer.Listeners 483 | AWS::ElasticLoadBalancing::LoadBalancer.Policies 484 | AWS::ElasticLoadBalancingV2::Listener 485 | AWS::ElasticLoadBalancingV2::Listener.Action 486 | AWS::ElasticLoadBalancingV2::Listener.Certificate 487 | AWS::ElasticLoadBalancingV2::ListenerCertificate 488 | AWS::ElasticLoadBalancingV2::ListenerCertificate.Certificate 489 | AWS::ElasticLoadBalancingV2::ListenerRule 490 | AWS::ElasticLoadBalancingV2::ListenerRule.Action 491 | AWS::ElasticLoadBalancingV2::ListenerRule.RuleCondition 492 | AWS::ElasticLoadBalancingV2::LoadBalancer 493 | AWS::ElasticLoadBalancingV2::LoadBalancer.LoadBalancerAttribute 494 | AWS::ElasticLoadBalancingV2::LoadBalancer.SubnetMapping 495 | AWS::ElasticLoadBalancingV2::TargetGroup 496 | AWS::ElasticLoadBalancingV2::TargetGroup.Matcher 497 | AWS::ElasticLoadBalancingV2::TargetGroup.TargetDescription 498 | AWS::ElasticLoadBalancingV2::TargetGroup.TargetGroupAttribute 499 | AWS::Elasticsearch::Domain 500 | AWS::Elasticsearch::Domain.EBSOptions 501 | AWS::Elasticsearch::Domain.ElasticsearchClusterConfig 502 | AWS::Elasticsearch::Domain.EncryptionAtRestOptions 503 | AWS::Elasticsearch::Domain.SnapshotOptions 504 | AWS::Elasticsearch::Domain.VPCOptions 505 | AWS::Events::Rule 506 | AWS::Events::Rule.EcsParameters 507 | AWS::Events::Rule.InputTransformer 508 | AWS::Events::Rule.KinesisParameters 509 | AWS::Events::Rule.RunCommandParameters 510 | AWS::Events::Rule.RunCommandTarget 511 | AWS::Events::Rule.SqsParameters 512 | AWS::Events::Rule.Target 513 | AWS::GameLift::Alias 514 | AWS::GameLift::Alias.RoutingStrategy 515 | AWS::GameLift::Build 516 | AWS::GameLift::Build.S3Location 517 | AWS::GameLift::Fleet 518 | AWS::GameLift::Fleet.IpPermission 519 | AWS::Glue::Classifier 520 | AWS::Glue::Classifier.GrokClassifier 521 | AWS::Glue::Classifier.JsonClassifier 522 | AWS::Glue::Classifier.XMLClassifier 523 | AWS::Glue::Connection 524 | AWS::Glue::Connection.ConnectionInput 525 | AWS::Glue::Connection.PhysicalConnectionRequirements 526 | AWS::Glue::Crawler 527 | AWS::Glue::Crawler.JdbcTarget 528 | AWS::Glue::Crawler.S3Target 529 | AWS::Glue::Crawler.Schedule 530 | AWS::Glue::Crawler.SchemaChangePolicy 531 | AWS::Glue::Crawler.Targets 532 | AWS::Glue::Database 533 | AWS::Glue::Database.DatabaseInput 534 | AWS::Glue::DevEndpoint 535 | AWS::Glue::Job 536 | AWS::Glue::Job.ConnectionsList 537 | AWS::Glue::Job.ExecutionProperty 538 | AWS::Glue::Job.JobCommand 539 | AWS::Glue::Partition 540 | AWS::Glue::Partition.Column 541 | AWS::Glue::Partition.Order 542 | AWS::Glue::Partition.PartitionInput 543 | AWS::Glue::Partition.SerdeInfo 544 | AWS::Glue::Partition.SkewedInfo 545 | AWS::Glue::Partition.StorageDescriptor 546 | AWS::Glue::Table 547 | AWS::Glue::Table.Column 548 | AWS::Glue::Table.Order 549 | AWS::Glue::Table.SerdeInfo 550 | AWS::Glue::Table.SkewedInfo 551 | AWS::Glue::Table.StorageDescriptor 552 | AWS::Glue::Table.TableInput 553 | AWS::Glue::Trigger 554 | AWS::Glue::Trigger.Action 555 | AWS::Glue::Trigger.Condition 556 | AWS::Glue::Trigger.Predicate 557 | AWS::GuardDuty::Detector 558 | AWS::GuardDuty::Filter 559 | AWS::GuardDuty::Filter.Condition 560 | AWS::GuardDuty::Filter.FindingCriteria 561 | AWS::GuardDuty::IPSet 562 | AWS::GuardDuty::Master 563 | AWS::GuardDuty::Member 564 | AWS::GuardDuty::ThreatIntelSet 565 | AWS::IAM::AccessKey 566 | AWS::IAM::Group 567 | AWS::IAM::Group.Policy 568 | AWS::IAM::InstanceProfile 569 | AWS::IAM::ManagedPolicy 570 | AWS::IAM::Policy 571 | AWS::IAM::Role 572 | AWS::IAM::Role.Policy 573 | AWS::IAM::ServiceLinkedRole 574 | AWS::IAM::User 575 | AWS::IAM::User.LoginProfile 576 | AWS::IAM::User.Policy 577 | AWS::IAM::UserToGroupAddition 578 | AWS::Inspector::AssessmentTarget 579 | AWS::Inspector::AssessmentTemplate 580 | AWS::Inspector::ResourceGroup 581 | AWS::IoT1Click::Device 582 | AWS::IoT1Click::Placement 583 | AWS::IoT1Click::Project 584 | AWS::IoT1Click::Project.DeviceTemplate 585 | AWS::IoT1Click::Project.PlacementTemplate 586 | AWS::IoT::Certificate 587 | AWS::IoT::Policy 588 | AWS::IoT::PolicyPrincipalAttachment 589 | AWS::IoT::Thing 590 | AWS::IoT::Thing.AttributePayload 591 | AWS::IoT::ThingPrincipalAttachment 592 | AWS::IoT::TopicRule 593 | AWS::IoT::TopicRule.Action 594 | AWS::IoT::TopicRule.CloudwatchAlarmAction 595 | AWS::IoT::TopicRule.CloudwatchMetricAction 596 | AWS::IoT::TopicRule.DynamoDBAction 597 | AWS::IoT::TopicRule.DynamoDBv2Action 598 | AWS::IoT::TopicRule.ElasticsearchAction 599 | AWS::IoT::TopicRule.FirehoseAction 600 | AWS::IoT::TopicRule.KinesisAction 601 | AWS::IoT::TopicRule.LambdaAction 602 | AWS::IoT::TopicRule.PutItemInput 603 | AWS::IoT::TopicRule.RepublishAction 604 | AWS::IoT::TopicRule.S3Action 605 | AWS::IoT::TopicRule.SnsAction 606 | AWS::IoT::TopicRule.SqsAction 607 | AWS::IoT::TopicRule.TopicRulePayload 608 | AWS::KMS::Alias 609 | AWS::KMS::Key 610 | AWS::Kinesis::Stream 611 | AWS::Kinesis::Stream.StreamEncryption 612 | AWS::KinesisAnalytics::Application 613 | AWS::KinesisAnalytics::Application.CSVMappingParameters 614 | AWS::KinesisAnalytics::Application.Input 615 | AWS::KinesisAnalytics::Application.InputLambdaProcessor 616 | AWS::KinesisAnalytics::Application.InputParallelism 617 | AWS::KinesisAnalytics::Application.InputProcessingConfiguration 618 | AWS::KinesisAnalytics::Application.InputSchema 619 | AWS::KinesisAnalytics::Application.JSONMappingParameters 620 | AWS::KinesisAnalytics::Application.KinesisFirehoseInput 621 | AWS::KinesisAnalytics::Application.KinesisStreamsInput 622 | AWS::KinesisAnalytics::Application.MappingParameters 623 | AWS::KinesisAnalytics::Application.RecordColumn 624 | AWS::KinesisAnalytics::Application.RecordFormat 625 | AWS::KinesisAnalytics::ApplicationOutput 626 | AWS::KinesisAnalytics::ApplicationOutput.DestinationSchema 627 | AWS::KinesisAnalytics::ApplicationOutput.KinesisFirehoseOutput 628 | AWS::KinesisAnalytics::ApplicationOutput.KinesisStreamsOutput 629 | AWS::KinesisAnalytics::ApplicationOutput.LambdaOutput 630 | AWS::KinesisAnalytics::ApplicationOutput.Output 631 | AWS::KinesisAnalytics::ApplicationReferenceDataSource 632 | AWS::KinesisAnalytics::ApplicationReferenceDataSource.CSVMappingParameters 633 | AWS::KinesisAnalytics::ApplicationReferenceDataSource.JSONMappingParameters 634 | AWS::KinesisAnalytics::ApplicationReferenceDataSource.MappingParameters 635 | AWS::KinesisAnalytics::ApplicationReferenceDataSource.RecordColumn 636 | AWS::KinesisAnalytics::ApplicationReferenceDataSource.RecordFormat 637 | AWS::KinesisAnalytics::ApplicationReferenceDataSource.ReferenceDataSource 638 | AWS::KinesisAnalytics::ApplicationReferenceDataSource.ReferenceSchema 639 | AWS::KinesisAnalytics::ApplicationReferenceDataSource.S3ReferenceDataSource 640 | AWS::KinesisFirehose::DeliveryStream 641 | AWS::KinesisFirehose::DeliveryStream.BufferingHints 642 | AWS::KinesisFirehose::DeliveryStream.CloudWatchLoggingOptions 643 | AWS::KinesisFirehose::DeliveryStream.CopyCommand 644 | AWS::KinesisFirehose::DeliveryStream.ElasticsearchBufferingHints 645 | AWS::KinesisFirehose::DeliveryStream.ElasticsearchDestinationConfiguration 646 | AWS::KinesisFirehose::DeliveryStream.ElasticsearchRetryOptions 647 | AWS::KinesisFirehose::DeliveryStream.EncryptionConfiguration 648 | AWS::KinesisFirehose::DeliveryStream.ExtendedS3DestinationConfiguration 649 | AWS::KinesisFirehose::DeliveryStream.KMSEncryptionConfig 650 | AWS::KinesisFirehose::DeliveryStream.KinesisStreamSourceConfiguration 651 | AWS::KinesisFirehose::DeliveryStream.ProcessingConfiguration 652 | AWS::KinesisFirehose::DeliveryStream.Processor 653 | AWS::KinesisFirehose::DeliveryStream.ProcessorParameter 654 | AWS::KinesisFirehose::DeliveryStream.RedshiftDestinationConfiguration 655 | AWS::KinesisFirehose::DeliveryStream.S3DestinationConfiguration 656 | AWS::KinesisFirehose::DeliveryStream.SplunkDestinationConfiguration 657 | AWS::KinesisFirehose::DeliveryStream.SplunkRetryOptions 658 | AWS::Lambda::Alias 659 | AWS::Lambda::Alias.AliasRoutingConfiguration 660 | AWS::Lambda::Alias.VersionWeight 661 | AWS::Lambda::EventSourceMapping 662 | AWS::Lambda::Function 663 | AWS::Lambda::Function.Code 664 | AWS::Lambda::Function.DeadLetterConfig 665 | AWS::Lambda::Function.Environment 666 | AWS::Lambda::Function.TracingConfig 667 | AWS::Lambda::Function.VpcConfig 668 | AWS::Lambda::Permission 669 | AWS::Lambda::Version 670 | AWS::Logs::Destination 671 | AWS::Logs::LogGroup 672 | AWS::Logs::LogStream 673 | AWS::Logs::MetricFilter 674 | AWS::Logs::MetricFilter.MetricTransformation 675 | AWS::Logs::SubscriptionFilter 676 | AWS::Neptune::DBCluster 677 | AWS::Neptune::DBClusterParameterGroup 678 | AWS::Neptune::DBInstance 679 | AWS::Neptune::DBParameterGroup 680 | AWS::Neptune::DBSubnetGroup 681 | AWS::OpsWorks::App 682 | AWS::OpsWorks::App.DataSource 683 | AWS::OpsWorks::App.EnvironmentVariable 684 | AWS::OpsWorks::App.Source 685 | AWS::OpsWorks::App.SslConfiguration 686 | AWS::OpsWorks::ElasticLoadBalancerAttachment 687 | AWS::OpsWorks::Instance 688 | AWS::OpsWorks::Instance.BlockDeviceMapping 689 | AWS::OpsWorks::Instance.EbsBlockDevice 690 | AWS::OpsWorks::Instance.TimeBasedAutoScaling 691 | AWS::OpsWorks::Layer 692 | AWS::OpsWorks::Layer.AutoScalingThresholds 693 | AWS::OpsWorks::Layer.LifecycleEventConfiguration 694 | AWS::OpsWorks::Layer.LoadBasedAutoScaling 695 | AWS::OpsWorks::Layer.Recipes 696 | AWS::OpsWorks::Layer.ShutdownEventConfiguration 697 | AWS::OpsWorks::Layer.VolumeConfiguration 698 | AWS::OpsWorks::Stack 699 | AWS::OpsWorks::Stack.ChefConfiguration 700 | AWS::OpsWorks::Stack.ElasticIp 701 | AWS::OpsWorks::Stack.RdsDbInstance 702 | AWS::OpsWorks::Stack.Source 703 | AWS::OpsWorks::Stack.StackConfigurationManager 704 | AWS::OpsWorks::UserProfile 705 | AWS::OpsWorks::Volume 706 | AWS::RDS::DBCluster 707 | AWS::RDS::DBCluster.ScalingConfiguration 708 | AWS::RDS::DBClusterParameterGroup 709 | AWS::RDS::DBInstance 710 | AWS::RDS::DBParameterGroup 711 | AWS::RDS::DBSecurityGroup 712 | AWS::RDS::DBSecurityGroup.Ingress 713 | AWS::RDS::DBSecurityGroupIngress 714 | AWS::RDS::DBSubnetGroup 715 | AWS::RDS::EventSubscription 716 | AWS::RDS::OptionGroup 717 | AWS::RDS::OptionGroup.OptionConfiguration 718 | AWS::RDS::OptionGroup.OptionSetting 719 | AWS::Redshift::Cluster 720 | AWS::Redshift::Cluster.LoggingProperties 721 | AWS::Redshift::ClusterParameterGroup 722 | AWS::Redshift::ClusterParameterGroup.Parameter 723 | AWS::Redshift::ClusterSecurityGroup 724 | AWS::Redshift::ClusterSecurityGroupIngress 725 | AWS::Redshift::ClusterSubnetGroup 726 | AWS::Route53::HealthCheck 727 | AWS::Route53::HealthCheck.AlarmIdentifier 728 | AWS::Route53::HealthCheck.HealthCheckConfig 729 | AWS::Route53::HealthCheck.HealthCheckTag 730 | AWS::Route53::HostedZone 731 | AWS::Route53::HostedZone.HostedZoneConfig 732 | AWS::Route53::HostedZone.HostedZoneTag 733 | AWS::Route53::HostedZone.QueryLoggingConfig 734 | AWS::Route53::HostedZone.VPC 735 | AWS::Route53::RecordSet 736 | AWS::Route53::RecordSet.AliasTarget 737 | AWS::Route53::RecordSet.GeoLocation 738 | AWS::Route53::RecordSetGroup 739 | AWS::Route53::RecordSetGroup.AliasTarget 740 | AWS::Route53::RecordSetGroup.GeoLocation 741 | AWS::Route53::RecordSetGroup.RecordSet 742 | AWS::S3::Bucket 743 | AWS::S3::Bucket.AbortIncompleteMultipartUpload 744 | AWS::S3::Bucket.AccelerateConfiguration 745 | AWS::S3::Bucket.AccessControlTranslation 746 | AWS::S3::Bucket.AnalyticsConfiguration 747 | AWS::S3::Bucket.BucketEncryption 748 | AWS::S3::Bucket.CorsConfiguration 749 | AWS::S3::Bucket.CorsRule 750 | AWS::S3::Bucket.DataExport 751 | AWS::S3::Bucket.Destination 752 | AWS::S3::Bucket.EncryptionConfiguration 753 | AWS::S3::Bucket.FilterRule 754 | AWS::S3::Bucket.InventoryConfiguration 755 | AWS::S3::Bucket.LambdaConfiguration 756 | AWS::S3::Bucket.LifecycleConfiguration 757 | AWS::S3::Bucket.LoggingConfiguration 758 | AWS::S3::Bucket.MetricsConfiguration 759 | AWS::S3::Bucket.NoncurrentVersionTransition 760 | AWS::S3::Bucket.NotificationConfiguration 761 | AWS::S3::Bucket.NotificationFilter 762 | AWS::S3::Bucket.QueueConfiguration 763 | AWS::S3::Bucket.RedirectAllRequestsTo 764 | AWS::S3::Bucket.RedirectRule 765 | AWS::S3::Bucket.ReplicationConfiguration 766 | AWS::S3::Bucket.ReplicationDestination 767 | AWS::S3::Bucket.ReplicationRule 768 | AWS::S3::Bucket.RoutingRule 769 | AWS::S3::Bucket.RoutingRuleCondition 770 | AWS::S3::Bucket.Rule 771 | AWS::S3::Bucket.S3KeyFilter 772 | AWS::S3::Bucket.ServerSideEncryptionByDefault 773 | AWS::S3::Bucket.ServerSideEncryptionRule 774 | AWS::S3::Bucket.SourceSelectionCriteria 775 | AWS::S3::Bucket.SseKmsEncryptedObjects 776 | AWS::S3::Bucket.StorageClassAnalysis 777 | AWS::S3::Bucket.TagFilter 778 | AWS::S3::Bucket.TopicConfiguration 779 | AWS::S3::Bucket.Transition 780 | AWS::S3::Bucket.VersioningConfiguration 781 | AWS::S3::Bucket.WebsiteConfiguration 782 | AWS::S3::BucketPolicy 783 | AWS::SDB::Domain 784 | AWS::SES::ConfigurationSet 785 | AWS::SES::ConfigurationSetEventDestination 786 | AWS::SES::ConfigurationSetEventDestination.CloudWatchDestination 787 | AWS::SES::ConfigurationSetEventDestination.DimensionConfiguration 788 | AWS::SES::ConfigurationSetEventDestination.EventDestination 789 | AWS::SES::ConfigurationSetEventDestination.KinesisFirehoseDestination 790 | AWS::SES::ReceiptFilter 791 | AWS::SES::ReceiptFilter.Filter 792 | AWS::SES::ReceiptFilter.IpFilter 793 | AWS::SES::ReceiptRule 794 | AWS::SES::ReceiptRule.Action 795 | AWS::SES::ReceiptRule.AddHeaderAction 796 | AWS::SES::ReceiptRule.BounceAction 797 | AWS::SES::ReceiptRule.LambdaAction 798 | AWS::SES::ReceiptRule.Rule 799 | AWS::SES::ReceiptRule.S3Action 800 | AWS::SES::ReceiptRule.SNSAction 801 | AWS::SES::ReceiptRule.StopAction 802 | AWS::SES::ReceiptRule.WorkmailAction 803 | AWS::SES::ReceiptRuleSet 804 | AWS::SES::Template 805 | AWS::SES::Template.Template 806 | AWS::SNS::Subscription 807 | AWS::SNS::Topic 808 | AWS::SNS::Topic.Subscription 809 | AWS::SNS::TopicPolicy 810 | AWS::SQS::Queue 811 | AWS::SQS::QueuePolicy 812 | AWS::SSM::Association 813 | AWS::SSM::Association.InstanceAssociationOutputLocation 814 | AWS::SSM::Association.ParameterValues 815 | AWS::SSM::Association.S3OutputLocation 816 | AWS::SSM::Association.Target 817 | AWS::SSM::Document 818 | AWS::SSM::MaintenanceWindowTask 819 | AWS::SSM::MaintenanceWindowTask.LoggingInfo 820 | AWS::SSM::MaintenanceWindowTask.MaintenanceWindowAutomationParameters 821 | AWS::SSM::MaintenanceWindowTask.MaintenanceWindowLambdaParameters 822 | AWS::SSM::MaintenanceWindowTask.MaintenanceWindowRunCommandParameters 823 | AWS::SSM::MaintenanceWindowTask.MaintenanceWindowStepFunctionsParameters 824 | AWS::SSM::MaintenanceWindowTask.NotificationConfig 825 | AWS::SSM::MaintenanceWindowTask.Target 826 | AWS::SSM::MaintenanceWindowTask.TaskInvocationParameters 827 | AWS::SSM::Parameter 828 | AWS::SSM::PatchBaseline 829 | AWS::SSM::PatchBaseline.PatchFilter 830 | AWS::SSM::PatchBaseline.PatchFilterGroup 831 | AWS::SSM::PatchBaseline.PatchSource 832 | AWS::SSM::PatchBaseline.Rule 833 | AWS::SSM::PatchBaseline.RuleGroup 834 | AWS::SSM::ResourceDataSync 835 | AWS::SageMaker::Endpoint 836 | AWS::SageMaker::EndpointConfig 837 | AWS::SageMaker::EndpointConfig.ProductionVariant 838 | AWS::SageMaker::Model 839 | AWS::SageMaker::Model.ContainerDefinition 840 | AWS::SageMaker::Model.VpcConfig 841 | AWS::SageMaker::NotebookInstance 842 | AWS::SageMaker::NotebookInstanceLifecycleConfig 843 | AWS::SageMaker::NotebookInstanceLifecycleConfig.NotebookInstanceLifecycleHook 844 | AWS::ServiceCatalog::AcceptedPortfolioShare 845 | AWS::ServiceCatalog::CloudFormationProduct 846 | AWS::ServiceCatalog::CloudFormationProduct.ProvisioningArtifactProperties 847 | AWS::ServiceCatalog::CloudFormationProvisionedProduct 848 | AWS::ServiceCatalog::CloudFormationProvisionedProduct.ProvisioningParameter 849 | AWS::ServiceCatalog::LaunchNotificationConstraint 850 | AWS::ServiceCatalog::LaunchRoleConstraint 851 | AWS::ServiceCatalog::LaunchTemplateConstraint 852 | AWS::ServiceCatalog::Portfolio 853 | AWS::ServiceCatalog::PortfolioPrincipalAssociation 854 | AWS::ServiceCatalog::PortfolioProductAssociation 855 | AWS::ServiceCatalog::PortfolioShare 856 | AWS::ServiceCatalog::TagOption 857 | AWS::ServiceCatalog::TagOptionAssociation 858 | AWS::ServiceDiscovery::Instance 859 | AWS::ServiceDiscovery::PrivateDnsNamespace 860 | AWS::ServiceDiscovery::PublicDnsNamespace 861 | AWS::ServiceDiscovery::Service 862 | AWS::ServiceDiscovery::Service.DnsConfig 863 | AWS::ServiceDiscovery::Service.DnsRecord 864 | AWS::ServiceDiscovery::Service.HealthCheckConfig 865 | AWS::ServiceDiscovery::Service.HealthCheckCustomConfig 866 | AWS::StepFunctions::Activity 867 | AWS::StepFunctions::StateMachine 868 | AWS::WAF::ByteMatchSet 869 | AWS::WAF::ByteMatchSet.ByteMatchTuple 870 | AWS::WAF::ByteMatchSet.FieldToMatch 871 | AWS::WAF::IPSet 872 | AWS::WAF::IPSet.IPSetDescriptor 873 | AWS::WAF::Rule 874 | AWS::WAF::Rule.Predicate 875 | AWS::WAF::SizeConstraintSet 876 | AWS::WAF::SizeConstraintSet.FieldToMatch 877 | AWS::WAF::SizeConstraintSet.SizeConstraint 878 | AWS::WAF::SqlInjectionMatchSet 879 | AWS::WAF::SqlInjectionMatchSet.FieldToMatch 880 | AWS::WAF::SqlInjectionMatchSet.SqlInjectionMatchTuple 881 | AWS::WAF::WebACL 882 | AWS::WAF::WebACL.ActivatedRule 883 | AWS::WAF::WebACL.WafAction 884 | AWS::WAF::XssMatchSet 885 | AWS::WAF::XssMatchSet.FieldToMatch 886 | AWS::WAF::XssMatchSet.XssMatchTuple 887 | AWS::WAFRegional::ByteMatchSet 888 | AWS::WAFRegional::ByteMatchSet.ByteMatchTuple 889 | AWS::WAFRegional::ByteMatchSet.FieldToMatch 890 | AWS::WAFRegional::IPSet 891 | AWS::WAFRegional::IPSet.IPSetDescriptor 892 | AWS::WAFRegional::Rule 893 | AWS::WAFRegional::Rule.Predicate 894 | AWS::WAFRegional::SizeConstraintSet 895 | AWS::WAFRegional::SizeConstraintSet.FieldToMatch 896 | AWS::WAFRegional::SizeConstraintSet.SizeConstraint 897 | AWS::WAFRegional::SqlInjectionMatchSet 898 | AWS::WAFRegional::SqlInjectionMatchSet.FieldToMatch 899 | AWS::WAFRegional::SqlInjectionMatchSet.SqlInjectionMatchTuple 900 | AWS::WAFRegional::WebACL 901 | AWS::WAFRegional::WebACL.Action 902 | AWS::WAFRegional::WebACL.Rule 903 | AWS::WAFRegional::WebACLAssociation 904 | AWS::WAFRegional::XssMatchSet 905 | AWS::WAFRegional::XssMatchSet.FieldToMatch 906 | AWS::WAFRegional::XssMatchSet.XssMatchTuple 907 | AWS::WorkSpaces::Workspace 908 | --------------------------------------------------------------------------------