├── .github └── PULL_REQUEST_TEMPLATE.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── disable_transition.js ├── setup-synthetic-tests-resources-stack-parameters.json ├── setup-synthetic-tests-resources-stack.yml ├── synthetic-test-runner.js ├── synthetic-tests-demo-resources-parameters.json └── synthetic-tests-demo-resources.yml /.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 | -------------------------------------------------------------------------------- /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/${GITHUB_ORG}/${GITHUB_REPO}/issues), or [recently closed](https://github.com/${GITHUB_ORG}/${GITHUB_REPO}/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/${GITHUB_ORG}/${GITHUB_REPO}/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/${GITHUB_ORG}/${GITHUB_REPO}/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 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AWS CodePipeline Synthetic Tests 2 | 3 | The resources in this repository will help you setup required AWS resources 4 | for building synthetic tests and use it to disable transitions in AWS CodePipeline. 5 | 6 | ## Prerequisites 7 | 8 | 1. Create an AWS CodeCommit repository with any name of your preference using AWS console or CLI. This document assumes that the name you chose is `aws-codepipeline-synthetic-tests`. 9 | 2. Clone the content of this repository to AWS CodeCommit repository created in the above step. See this [article](http://docs.aws.amazon.com/codecommit/latest/userguide/how-to-migrate-repository.html) for details on cloning a GitHub repository to AWS CodeCommit. 10 | 3. Download AWS CodeDeploy sample application for Linux using this [link](https://s3.amazonaws.com/aws-codedeploy-us-east-1/samples/latest/SampleApp_Linux.zip). 11 | 4. Upload this application in a version enabled Amazon S3 bucket you own. Note down both the bucket name and object key. You will need in later steps. 12 | 5. Create an Amazon EC2 key pair if you don't have one already. 13 | 14 | ## Steps 15 | Run following steps in the local workspace where GitHub repository was cloned: 16 | 17 | 1. If you chose a different AWS CodeCommit repository name, replace `ParameterValue` in `setup-synthetic-tests-resources-stack-parameters.json` file with the name you chose. 18 | 2. Update `synthetic-tests-demo-resources-parameters.json` file to replace parameter values: 19 | * `CodeDeploySampleAppS3BucketName`: Amazon S3 bucket name from step 4 in Prerequisites section 20 | * `CodeDeploySampleAppS3ObjectKey` : The object key from step 4 in Prerequisites section 21 | * `KeyPairName` : Amazon EC2 key pair name 22 | * `YourIP` : IP address to connect to SSH from. Check http://checkip.amazonaws.com/ to find yours. 23 | 3. Create a new CloudFormation stack using AWS CloudFormation template `setup-synthetic-tests-resources-stack.yml` and parameter file `setup-synthetic-tests-resources-stack-parameters.json`. See this [article](https://aws.amazon.com/blogs/devops/passing-parameters-to-cloudformation-stacks-with-the-aws-cli-and-powershell/) for the details on how to pass parameters file using CLI. 24 | 25 | ``` 26 | aws cloudformation create-stack --stack-name SetupSyntheticTestsDemoResourcesStack --template-body file:///aws-codepipeline-synthetic-tests/setup-synthetic-tests-resources-stack.yml --capabilities CAPABILITY_IAM --parameters file:///aws-codepipeline-synthetic-tests/setup-synthetic-tests-resources-stack-parameters.json 27 | ``` 28 | 4. Step 3 will create an AWS CodePipeline named `SetupSyntheticTestsDemoResources-Pipeline`. This pipeline will use AWS CloudFormation integration with AWS CodePipeline to publish AWS Lambda functions to Amazon S3 and create a new stack using template `synthetic-tests-demo-resources.yml` that contains actual AWS resources used in demo including a new AWS CodePipeline named `SyntheticTestsDemoPipeline`. 29 | 5. Above step will set up following things: 30 | * A new AWS CodePipeline named `SyntheticTestsDemoPipeline` with an AWS CodeDeploy Deploy stage. 31 | * AWS Lambda function that runs periodically to test the website created by Amazon CodeDeploy sample application 32 | and to send failure metrics to Amazon CloudWatch. 33 | * If the published metrics don't meet specified criteria, it triggers an Amazon CloudWatch alarm. 34 | * Amazon CloudWatch alarm sends notification to Amazon SNS topic which in turn invokes AWS Lambda function 35 | to disable the transition to Deploy stage in pipeline `SyntheticTestsDemoPipeline`. 36 | 37 | ## Cleanup 38 | When no longer required, please remember to delete the stacks using AWS CloudFormation console or CLI to avoid getting charged. 39 | 40 | ## License 41 | This plugin is open sourced and licensed under Apache 2.0. See the LICENSE file 42 | for more information. 43 | -------------------------------------------------------------------------------- /disable_transition.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | var aws = require('aws-sdk'); 16 | var codepipeline = new aws.CodePipeline(); 17 | 18 | exports.handler = (event, context, callback) => { 19 | 20 | var params = { 21 | pipelineName: process.env.PIPELINE_NAME, 22 | stageName: process.env.STAGE_NAME, 23 | transitionType: "Inbound", 24 | reason: "Disabled because synthetic tests were failing" 25 | }; 26 | 27 | codepipeline.disableStageTransition(params, function(err, data) { 28 | if (err) { 29 | console.log(err, err.stack); // an error occurred 30 | callback("Unable to disable the transition. Error: " + JSON.stringify(err)); 31 | } else { 32 | console.log(data); // successful response 33 | callback(null, "Successfully disabled the transition for parameters: " + JSON.stringify(params)); 34 | } 35 | }); 36 | }; 37 | -------------------------------------------------------------------------------- /setup-synthetic-tests-resources-stack-parameters.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "ParameterKey": "DemoResourcesCodeCommitRepo", 4 | "ParameterValue": "aws-codepipeline-synthetic-tests" 5 | } 6 | ] -------------------------------------------------------------------------------- /setup-synthetic-tests-resources-stack.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Description: 'AWS Cloudformation template to help create synthetic tests demo resources.' 3 | 4 | Parameters: 5 | DemoResourcesCodeCommitRepo: 6 | Description: AWS CodeCommit repository name which contains the demo resources 7 | Type: String 8 | Default: "aws-codepipeline-synthetic-tests" 9 | DemoResourcesCodeCommitRepoBranch: 10 | Description: AWS CodeCommit repository branch 11 | Type: String 12 | Default: "master" 13 | 14 | Resources: 15 | 16 | ArtifactStoreBucket: 17 | Type: AWS::S3::Bucket 18 | 19 | Pipeline: 20 | Type: AWS::CodePipeline::Pipeline 21 | Properties: 22 | ArtifactStore: 23 | Location: !Ref 'ArtifactStoreBucket' 24 | Type: S3 25 | Name: "SetupSyntheticTestsDemoResources-Pipeline" 26 | RoleArn: !GetAtt [PipelineRole, Arn] 27 | Stages: 28 | - Name: Source 29 | Actions: 30 | - Name: DemoResourcesSource 31 | ActionTypeId: 32 | Category: Source 33 | Owner: AWS 34 | Provider: CodeCommit 35 | Version: '1' 36 | Configuration: 37 | RepositoryName: !Ref DemoResourcesCodeCommitRepo 38 | BranchName: !Ref DemoResourcesCodeCommitRepoBranch 39 | OutputArtifacts: 40 | - Name: DemoArtifacts 41 | RunOrder: '1' 42 | - Name: CloudformationDeploy 43 | Actions: 44 | - Name: CreateDemoResources 45 | ActionTypeId: 46 | Category: Deploy 47 | Owner: AWS 48 | Provider: CloudFormation 49 | Version: '1' 50 | InputArtifacts: 51 | - Name: DemoArtifacts 52 | Configuration: 53 | ActionMode: CREATE_UPDATE 54 | RoleArn: !GetAtt [CloudFormationRole, Arn] 55 | StackName: SyntheticTestsDemoResources 56 | TemplatePath: DemoArtifacts::synthetic-tests-demo-resources.yml 57 | TemplateConfiguration: DemoArtifacts::synthetic-tests-demo-resources-parameters.json 58 | ParameterOverrides: | 59 | { 60 | "DemoResourcesS3BucketName" : { "Fn::GetArtifactAtt" : ["DemoArtifacts", "BucketName"]}, 61 | "DemoResourcesS3ObjectKey" : { "Fn::GetArtifactAtt" : ["DemoArtifacts", "ObjectKey"]} 62 | } 63 | Capabilities: CAPABILITY_IAM 64 | RunOrder: '1' 65 | 66 | CloudFormationRole: 67 | Type: AWS::IAM::Role 68 | Properties: 69 | AssumeRolePolicyDocument: 70 | Statement: 71 | - Action: ['sts:AssumeRole'] 72 | Effect: Allow 73 | Principal: 74 | Service: [cloudformation.amazonaws.com] 75 | Version: '2012-10-17' 76 | Path: / 77 | Policies: 78 | - PolicyName: CloudFormationRole 79 | PolicyDocument: 80 | Version: '2012-10-17' 81 | Statement: 82 | - Action: '*' 83 | Effect: Allow 84 | Resource: '*' 85 | 86 | PipelineRole: 87 | Type: AWS::IAM::Role 88 | Properties: 89 | AssumeRolePolicyDocument: 90 | Statement: 91 | - Action: ['sts:AssumeRole'] 92 | Effect: Allow 93 | Principal: 94 | Service: [codepipeline.amazonaws.com] 95 | Version: '2012-10-17' 96 | Path: / 97 | Policies: 98 | - PolicyName: CodePipelineAccess 99 | PolicyDocument: 100 | Version: '2012-10-17' 101 | Statement: 102 | - Effect: Allow 103 | Action: 104 | - "s3:GetObject" 105 | - "s3:PutObject" 106 | Resource: 107 | - "Fn::Join": ["", ["arn:aws:s3:::", {"Ref": "ArtifactStoreBucket"}, "/*" ]] 108 | - Effect: "Allow" 109 | Action: 110 | - "s3:ListBucket" 111 | Resource: 112 | - "Fn::Join": ["", ["arn:aws:s3:::", {"Ref": "ArtifactStoreBucket"}]] 113 | - Effect: Allow 114 | Action: 115 | - 'cloudformation:CreateStack' 116 | - 'cloudformation:DescribeStacks' 117 | - 'cloudformation:DeleteStack' 118 | - 'cloudformation:UpdateStack' 119 | - 'cloudformation:CreateChangeSet' 120 | - 'cloudformation:ExecuteChangeSet' 121 | - 'cloudformation:DeleteChangeSet' 122 | - 'cloudformation:DescribeChangeSet' 123 | - 'cloudformation:SetStackPolicy' 124 | Resource: 125 | - "Fn::Join": ["", ["arn:aws:cloudformation:", { "Ref" : "AWS::Region" }, ":", { "Ref" : "AWS::AccountId" }, ":stack/", "SyntheticTestsDemoResources"]] 126 | - "Fn::Join": ["", ["arn:aws:cloudformation:", { "Ref" : "AWS::Region" }, ":", { "Ref" : "AWS::AccountId" }, ":stack/", "SyntheticTestsDemoResources/*"]] 127 | - Effect: Allow 128 | Action: 129 | - 'iam:PassRole' 130 | Resource: 131 | - !GetAtt [CloudFormationRole, Arn] 132 | - Effect: Allow 133 | Action: 134 | - "codecommit:GetBranch" 135 | - "codecommit:GetCommit" 136 | - "codecommit:UploadArchive" 137 | - "codecommit:GetUploadArchiveStatus" 138 | - "codecommit:CancelUploadArchive" 139 | Resource: 140 | - "Fn::Join": ["", ["arn:aws:codecommit:", { "Ref" : "AWS::Region" }, ":", { "Ref" : "AWS::AccountId" }, ":", {"Ref" : "DemoResourcesCodeCommitRepo"}]] -------------------------------------------------------------------------------- /synthetic-test-runner.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | var http = require("http"); 16 | var aws = require("aws-sdk"); 17 | var cloudWatch = new aws.CloudWatch(); 18 | 19 | exports.handler = (event, context, callback) => { 20 | 21 | var options = { 22 | host: process.env.WEBSITE_URL, 23 | port: 80, 24 | path: '/' 25 | }; 26 | 27 | // In real world scenarios, deeper health checks should be done. 28 | var content = ""; 29 | var req = http.request(options, function(res) { 30 | res.setEncoding("utf8"); 31 | res.on("data", function(chunk) { 32 | content += chunk; 33 | }); 34 | 35 | res.on("end", function() { 36 | evaluateContent(content); 37 | }); 38 | }); 39 | 40 | req.end(); 41 | 42 | var evaluateContent = function(content) { 43 | if (content.indexOf("AWS CodePipeline") != -1) { 44 | emitCloudWatchMetrics(0); 45 | } else { 46 | emitCloudWatchMetrics(1); 47 | } 48 | }; 49 | 50 | var buildMetricsParams = function(count) { 51 | return { 52 | MetricData: [{ 53 | MetricName: process.env.METRIC_NAME, 54 | Timestamp: new Date, 55 | Value: count, 56 | Unit: "Count" 57 | }], 58 | Namespace: process.env.METRIC_NAMESPACE 59 | } 60 | }; 61 | 62 | var emitCloudWatchMetrics = function(failure) { 63 | cloudWatch.putMetricData(buildMetricsParams(failure), function(err, data) { 64 | if (err) { 65 | console.log(err, err.stack); // an error occurred 66 | callback("Synthetic Test Failure"); 67 | } else { 68 | console.log(data); // successful response 69 | callback(null, "Synthetic Test Successful"); 70 | } 71 | }); 72 | }; 73 | }; 74 | -------------------------------------------------------------------------------- /synthetic-tests-demo-resources-parameters.json: -------------------------------------------------------------------------------- 1 | { 2 | "Parameters" : { 3 | "CodeDeploySampleAppS3BucketName" : "", 4 | "CodeDeploySampleAppS3ObjectKey" : "", 6 | "YourIP" : "IP address to connect to SSH from. Check http://checkip.amazonaws.com/ to find yours." 7 | } 8 | } -------------------------------------------------------------------------------- /synthetic-tests-demo-resources.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: "2010-09-09" 2 | Description: "AWS CloudFormation template which contains the resources for synthetic tests demo." 3 | Parameters: 4 | DemoResourcesS3BucketName: 5 | Description: Amazon S3 bucket where demo resources zip file was uploaded to. 6 | Type: String 7 | DemoResourcesS3ObjectKey: 8 | Description: Amazon S3 object key with which demo resources zip file was uploaded to. 9 | Type: String 10 | CodeDeploySampleAppS3BucketName: 11 | Description: Amazon S3 bucket which contains AWS CodeDeploy sample app. 12 | Type: String 13 | CodeDeploySampleAppS3ObjectKey: 14 | Description: Amazon S3 object key of AWS CodeDeploy sample app. 15 | Type: String 16 | KeyPairName: 17 | Description: The name of an existing Amazon EC2 key pair to enable SSH or RDP access. 18 | to the instances. 19 | Type: String 20 | MinLength: '1' 21 | MaxLength: '255' 22 | AllowedPattern: "[\\x20-\\x7E]*" 23 | ConstraintDescription: Can contain only ASCII characters. 24 | YourIP: 25 | Description: "IP address to connect to SSH from. Check http://checkip.amazonaws.com/ to find yours." 26 | Type: String 27 | Default: "0.0.0.0/0" 28 | 29 | Mappings: 30 | RegionOS2AMI: 31 | us-east-1: 32 | Linux: ami-7c807d14 33 | us-west-2: 34 | Linux: ami-1b3b462b 35 | eu-west-1: 36 | Linux: ami-672ce210 37 | ap-southeast-2: 38 | Linux: ami-6bf99c51 39 | ap-southeast-1: 40 | Linux: ami-c9b572aa 41 | us-west-1: 42 | Linux: ami-d5ea86b5 43 | eu-central-1: 44 | Linux: ami-ae221fb3 45 | ap-northeast-1: 46 | Linux: ami-25dd9324 47 | sa-east-1: 48 | Linux: ami-d412aab8 49 | Constants: 50 | Pipeline: 51 | Name: SyntheticTestsDemoPipeline 52 | SourceStageName: Source 53 | DeployStageName: ProductionDeploy 54 | CloudWatchMetrics: 55 | Namespace: SyntheticTestMetrics 56 | Name: Failure 57 | 58 | Resources: 59 | # The instance will use this role to access S3 60 | EC2Role: 61 | Type: "AWS::IAM::Role" 62 | Properties: 63 | AssumeRolePolicyDocument: 64 | Statement: 65 | - Sid: "" 66 | Effect: "Allow" 67 | Principal: 68 | Service: 69 | - "ec2.amazonaws.com" 70 | Action: "sts:AssumeRole" 71 | Policies: 72 | - PolicyName: "s3" 73 | PolicyDocument: 74 | Version: "2012-10-17" 75 | Statement: 76 | - Effect: "Allow" 77 | Action: 78 | - "s3:GetObject" 79 | Resource: 80 | - "Fn::Join": ["", ["arn:aws:s3:::", {"Ref": "ArtifactStoreBucket"}, "/*" ]] 81 | - "Fn::Join": ["", ["arn:aws:s3:::aws-codedeploy-", {"Ref": "AWS::Region"}, "/*" ]] 82 | 83 | 84 | EC2InstanceProfile: 85 | Type: "AWS::IAM::InstanceProfile" 86 | Properties: 87 | Roles: 88 | - !Ref EC2Role 89 | 90 | SecurityGroup: 91 | Type: AWS::EC2::SecurityGroup 92 | Properties: 93 | GroupDescription: "Enable HTTP access via port 80 and SSH access." 94 | SecurityGroupIngress: 95 | - IpProtocol: tcp 96 | FromPort: "80" 97 | ToPort: "80" 98 | CidrIp: "0.0.0.0/0" 99 | - IpProtocol: tcp 100 | FromPort: 22 101 | ToPort: 22 102 | CidrIp: !Ref YourIP 103 | 104 | LaunchConfiguration: 105 | Type: "AWS::AutoScaling::LaunchConfiguration" 106 | Properties: 107 | IamInstanceProfile: !Ref EC2InstanceProfile 108 | ImageId: { "Fn::FindInMap": ["RegionOS2AMI", { "Ref" : "AWS::Region" } , "Linux"]} 109 | InstanceType: t1.micro 110 | KeyName: 111 | !Ref KeyPairName 112 | SecurityGroups: 113 | - !Ref SecurityGroup 114 | UserData: 115 | "Fn::Base64": 116 | "Fn::Join": 117 | - "" 118 | - [ 119 | "#!/bin/bash -xe\n", 120 | 121 | "/usr/bin/yum -y update\n", 122 | "/usr/bin/yum install -y ruby\n", 123 | "/usr/bin/yum install -y aws-cli\n", 124 | "cd /home/ec2-user/\n", 125 | "/usr/bin/aws s3 cp s3://aws-codedeploy-", { "Ref" : "AWS::Region" }, "/latest/install . --region ", { "Ref" : "AWS::Region" }, "\n", 126 | "/bin/chmod +x ./install\n", 127 | "./install auto\n" 128 | ] 129 | 130 | ElasticLoadBalancer: 131 | Type: AWS::ElasticLoadBalancing::LoadBalancer 132 | Properties: 133 | AvailabilityZones: { "Fn::GetAZs" : { "Ref" : "AWS::Region" } } 134 | Listeners: 135 | - LoadBalancerPort: '80' 136 | InstancePort: '80' 137 | Protocol: HTTP 138 | SecurityGroups: 139 | - !GetAtt [SecurityGroup, GroupId] 140 | 141 | AutoscalingGroup: 142 | Type: "AWS::AutoScaling::AutoScalingGroup" 143 | Properties: 144 | LoadBalancerNames : 145 | - !Ref ElasticLoadBalancer 146 | AvailabilityZones: { "Fn::GetAZs" : { "Ref" : "AWS::Region" } } 147 | DesiredCapacity: 1 148 | LaunchConfigurationName: !Ref LaunchConfiguration 149 | MinSize: "1" 150 | MaxSize: "3" 151 | 152 | CodeDeployTrustRole: 153 | Type: "AWS::IAM::Role" 154 | Properties: 155 | AssumeRolePolicyDocument: 156 | Statement: 157 | - Sid: "" 158 | Effect: "Allow" 159 | Principal: 160 | Service: 161 | - "codedeploy.amazonaws.com" 162 | Action: "sts:AssumeRole" 163 | ManagedPolicyArns: 164 | - "arn:aws:iam::aws:policy/service-role/AWSCodeDeployRole" 165 | Path: "/" 166 | 167 | CodeDeployApplication: 168 | Type: "AWS::CodeDeploy::Application" 169 | 170 | CodeDeployDeploymentGroup: 171 | Type: "AWS::CodeDeploy::DeploymentGroup" 172 | Properties: 173 | ApplicationName: !Ref CodeDeployApplication 174 | ServiceRoleArn: !GetAtt [CodeDeployTrustRole, Arn] 175 | AutoScalingGroups: 176 | - !Ref AutoscalingGroup 177 | 178 | ArtifactStoreBucket: 179 | Type: AWS::S3::Bucket 180 | 181 | Pipeline: 182 | Type: AWS::CodePipeline::Pipeline 183 | Properties: 184 | ArtifactStore: 185 | Location: !Ref ArtifactStoreBucket 186 | Type: S3 187 | Name: !FindInMap [ Constants, Pipeline, Name] 188 | RoleArn: !GetAtt [PipelineRole, Arn] 189 | Stages: 190 | - Name: !FindInMap [ Constants, Pipeline, SourceStageName] 191 | Actions: 192 | - Name: S3Source 193 | ActionTypeId: 194 | Category: Source 195 | Owner: AWS 196 | Provider: S3 197 | Version: '1' 198 | Configuration: 199 | S3Bucket: !Ref CodeDeploySampleAppS3BucketName 200 | S3ObjectKey: !Ref CodeDeploySampleAppS3ObjectKey 201 | OutputArtifacts: 202 | - Name: CodeDeployArtifacts 203 | RunOrder: '1' 204 | - Name: !FindInMap [ Constants, Pipeline, DeployStageName] 205 | Actions: 206 | - Name: CodeDeployApp 207 | ActionTypeId: 208 | Category: Deploy 209 | Owner: AWS 210 | Provider: CodeDeploy 211 | Version: '1' 212 | InputArtifacts: 213 | - Name: CodeDeployArtifacts 214 | Configuration: 215 | ApplicationName: !Ref CodeDeployApplication 216 | DeploymentGroupName: !Ref CodeDeployDeploymentGroup 217 | RunOrder: '1' 218 | 219 | PipelineRole: 220 | Type: AWS::IAM::Role 221 | Properties: 222 | AssumeRolePolicyDocument: 223 | Statement: 224 | - Action: ['sts:AssumeRole'] 225 | Effect: Allow 226 | Principal: 227 | Service: [codepipeline.amazonaws.com] 228 | Version: '2012-10-17' 229 | Path: / 230 | Policies: 231 | - PolicyName: CodePipelineAccess 232 | PolicyDocument: 233 | Version: '2012-10-17' 234 | Statement: 235 | - Action: 236 | - "s3:GetObject" 237 | - "s3:GetObjectVersion" 238 | Resource: 239 | - "Fn::Join": ["", ["arn:aws:s3:::", {"Ref": "CodeDeploySampleAppS3BucketName"}, "/*"]] 240 | Effect: Allow 241 | - Action: 242 | - "s3:GetBucketVersioning" 243 | Resource: 244 | - "Fn::Join": ["", ["arn:aws:s3:::", {"Ref": "CodeDeploySampleAppS3BucketName"}]] 245 | Effect: Allow 246 | - Action: 247 | - "s3:GetObject" 248 | - "s3:PutObject" 249 | Resource: 250 | - "Fn::Join": ["", ["arn:aws:s3:::", {"Ref": "ArtifactStoreBucket"}, "/*" ]] 251 | Effect: Allow 252 | - Effect: "Allow" 253 | Action: 254 | - "s3:ListBucket" 255 | Resource: 256 | - "Fn::Join": ["", ["arn:aws:s3:::", {"Ref": "ArtifactStoreBucket"}]] 257 | - Effect: Allow 258 | Action: 259 | - "codedeploy:CreateDeployment" 260 | - "codedeploy:GetApplicationRevision" 261 | - "codedeploy:GetDeployment" 262 | - "codedeploy:GetDeploymentConfig" 263 | - "codedeploy:RegisterApplicationRevision" 264 | Resource: "*" 265 | 266 | DisableStageTransitionFunctionExecutionRole: 267 | Type: AWS::IAM::Role 268 | Properties: 269 | AssumeRolePolicyDocument: 270 | Statement: 271 | - Action: ['sts:AssumeRole'] 272 | Effect: Allow 273 | Principal: 274 | Service: [lambda.amazonaws.com] 275 | Version: '2012-10-17' 276 | Path: / 277 | Policies: 278 | - PolicyName: CodePipelineAccess 279 | PolicyDocument: 280 | Version: '2012-10-17' 281 | Statement: 282 | - Effect: Allow 283 | Action: 284 | - "codepipeline:DisableStageTransition" 285 | Resource: 286 | - "Fn::Join": ["", ["arn:aws:codepipeline:", { "Ref" : "AWS::Region" }, ":", { "Ref" : "AWS::AccountId" }, ":", {"Ref": "Pipeline"}, "/*"]] 287 | - Effect: Allow 288 | Action: 289 | - "logs:CreateLogGroup" 290 | - "logs:CreateLogStream" 291 | - "logs:PutLogEvents" 292 | Resource: "arn:aws:logs:*:*:*" 293 | 294 | DisableStageTransitionLambdaFunction: 295 | Type: AWS::Lambda::Function 296 | Properties: 297 | Handler: "disable_transition.handler" 298 | Role: !GetAtt [DisableStageTransitionFunctionExecutionRole, Arn] 299 | Code: 300 | S3Bucket: !Ref DemoResourcesS3BucketName 301 | S3Key: !Ref DemoResourcesS3ObjectKey 302 | Runtime: nodejs4.3 303 | Timeout: 25 304 | Environment: 305 | Variables: 306 | PIPELINE_NAME: !FindInMap [ Constants, Pipeline, Name] 307 | STAGE_NAME: !FindInMap [ Constants, Pipeline, DeployStageName] 308 | 309 | DisableStageTransitionInvokePermission: 310 | Type: AWS::Lambda::Permission 311 | Properties: 312 | FunctionName: !GetAtt [DisableStageTransitionLambdaFunction, Arn] 313 | Action: "lambda:InvokeFunction" 314 | Principal: "sns.amazonaws.com" 315 | SourceArn: !Ref SyntheticTestFailureSNSNotification 316 | 317 | SyntheticTestFailureSNSNotification: 318 | Type: AWS::SNS::Topic 319 | Properties: 320 | Subscription: 321 | - Protocol: "lambda" 322 | Endpoint: !GetAtt [DisableStageTransitionLambdaFunction, Arn] 323 | 324 | SyntheticTestFailureCloudWatchAlarm: 325 | Type: AWS::CloudWatch::Alarm 326 | Properties: 327 | ActionsEnabled: true 328 | AlarmActions: 329 | - !Ref SyntheticTestFailureSNSNotification 330 | ComparisonOperator: GreaterThanOrEqualToThreshold 331 | # Set to a higher value to allow instances and load balancer to become healthy 332 | EvaluationPeriods: 10 333 | Namespace: !FindInMap [ Constants, CloudWatchMetrics, Namespace] 334 | MetricName: !FindInMap [ Constants, CloudWatchMetrics, Name] 335 | Period: 60 336 | Statistic: Sum 337 | Threshold: 1 338 | 339 | SyntheticTestFunctionExecutionRole: 340 | Type: AWS::IAM::Role 341 | Properties: 342 | AssumeRolePolicyDocument: 343 | Statement: 344 | - Action: ['sts:AssumeRole'] 345 | Effect: Allow 346 | Principal: 347 | Service: [lambda.amazonaws.com] 348 | Version: '2012-10-17' 349 | Path: / 350 | Policies: 351 | - PolicyName: CloudWatchAccess 352 | PolicyDocument: 353 | Version: '2012-10-17' 354 | Statement: 355 | - Effect: Allow 356 | Action: 357 | - "logs:CreateLogGroup" 358 | - "logs:CreateLogStream" 359 | - "logs:PutLogEvents" 360 | Resource: "arn:aws:logs:*:*:*" 361 | - Effect: Allow 362 | Action: 363 | - "cloudwatch:PutMetricData" 364 | Resource: '*' 365 | 366 | SyntheticTestRunnerLambdaFunction: 367 | Type: AWS::Lambda::Function 368 | Properties: 369 | Handler: "synthetic-test-runner.handler" 370 | Role: !GetAtt [SyntheticTestFunctionExecutionRole, Arn] 371 | Code: 372 | S3Bucket: !Ref DemoResourcesS3BucketName 373 | S3Key: !Ref DemoResourcesS3ObjectKey 374 | Runtime: "nodejs4.3" 375 | Timeout: "25" 376 | Environment: 377 | Variables: 378 | WEBSITE_URL: !GetAtt [ElasticLoadBalancer, DNSName] 379 | METRIC_NAMESPACE: !FindInMap [ Constants, CloudWatchMetrics, Namespace] 380 | METRIC_NAME: !FindInMap [ Constants, CloudWatchMetrics, Name] 381 | 382 | SyntheticTestRunnerInvokePermission: 383 | Type: AWS::Lambda::Permission 384 | Properties: 385 | FunctionName: !GetAtt [SyntheticTestRunnerLambdaFunction, Arn] 386 | Action: "lambda:InvokeFunction" 387 | Principal: "events.amazonaws.com" 388 | SourceArn: !GetAtt [SyntheticTestScheduleTrigger, Arn] 389 | 390 | SyntheticTestScheduleTrigger: 391 | DependsOn: Pipeline 392 | Type: AWS::Events::Rule 393 | Properties: 394 | ScheduleExpression: rate(1 minute) 395 | State: ENABLED 396 | Targets: 397 | - Arn: !GetAtt [SyntheticTestRunnerLambdaFunction, Arn] 398 | Id: "InvokeSyntheticTestRunner" 399 | --------------------------------------------------------------------------------