forked from aws/aws-cdk
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(synthetics): Synthetics L2 Support (aws#8824)
This PR specifies an implementation for a CloudWatch Canary. It will be implemented in milestones specified below. Closes aws#7687. Currently, this PR implements up to **Milestone 2**. **Milestone 1**: This implementation allows customers to specify a canary with these properties: - [x] `artifactBucket: IBucket` - [x] `role: IRole` - [x] `timeToLive: Duration` - [x] `schedule: Schedule` - [x] `startAfterCreation: boolean` - [x] `successRetentionPeriod: Duration` - [x] `failureRetentionPeriod: Duration` - [x] `canaryName: string` And: - [x] generate `name` for users if not specified - [x] metric methods that reference those emitted by CloudWatch **Milestone 2**: This is the next step needed to allow customers to specify their own canary scripts: - [x] `test:Test` - [x] `Test` class with static method `Test.custom()` - [x] `Code` class with static method `Code.inline()` - [x] `Code.fromAsset()` - [x] validate correct folder structure for assets `nodejs/node_modules` - [x] validate correct file name - [x] `Code.fromBucket()` **Milestone 3**: These are features that make a more robust Canary API: - [ ] static method `Test.apiEndpoint()` - [ ] additional static method templates for `Test` - [ ] support runConfig properties - `memorySize` and `timeout` [README Rendered version](https://github.com/aws/aws-cdk/blob/feca976ed2dbd0dc1e2416210cc967fa53a4309a/packages/%40aws-cdk/aws-synthetics/README.md) ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
- Loading branch information
Showing
18 changed files
with
1,925 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,16 +1,148 @@ | ||
## AWS::Synthetics Construct Library | ||
## Amazon CloudWatch Synthetics Construct Library | ||
|
||
<!--BEGIN STABILITY BANNER--> | ||
--- | ||
|
||
![cfn-resources: Stable](https://img.shields.io/badge/cfn--resources-stable-success.svg?style=for-the-badge) | ||
|
||
> All classes with the `Cfn` prefix in this module ([CFN Resources](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) are always stable and safe to use. | ||
![cdk-constructs: Experimental](https://img.shields.io/badge/cdk--constructs-experimental-important.svg?style=for-the-badge) | ||
|
||
> The APIs of higher level constructs in this module are experimental and under active development. They are subject to non-backward compatible changes or removal in any future version. These are not subject to the [Semantic Versioning](https://semver.org/) model and breaking changes will be announced in the release notes. This means that while you may use them, you may need to update your source code when upgrading to a newer version of this package. | ||
--- | ||
<!--END STABILITY BANNER--> | ||
|
||
This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. | ||
Amazon CloudWatch Synthetics allow you to monitor your application by generating **synthetic** traffic. The traffic is produced by a **canary**: a configurable script that runs on a schedule. You configure the canary script to follow the same routes and perform the same actions as a user, which allows you to continually verify your user experience even when you don't have any traffic on your applications. | ||
|
||
## Canary | ||
|
||
To illustrate how to use a canary, assume your application defines the following endpoint: | ||
|
||
```bash | ||
% curl "https://api.example.com/user/books/topbook/" | ||
The Hitchhikers Guide to the Galaxy | ||
|
||
``` | ||
|
||
The below code defines a canary that will hit the `books/topbook` endpoint every 5 minutes: | ||
|
||
```ts | ||
import * as synthetics from '@aws-cdk/aws-synthetics'; | ||
|
||
const canary = new synthetics.Canary(this, 'MyCanary', { | ||
schedule: synthetics.Schedule.rate(Duration.minutes(5)), | ||
test: Test.custom({ | ||
code: Code.fromAsset(path.join(__dirname, 'canary'))), | ||
handler: 'index.handler', | ||
}), | ||
}); | ||
``` | ||
|
||
The following is an example of an `index.js` file which exports the `handler` function: | ||
|
||
```js | ||
var synthetics = require('Synthetics'); | ||
const log = require('SyntheticsLogger'); | ||
|
||
const pageLoadBlueprint = async function () { | ||
|
||
// INSERT URL here | ||
const URL = "https://api.example.com/user/books/topbook/"; | ||
|
||
let page = await synthetics.getPage(); | ||
const response = await page.goto(URL, {waitUntil: 'domcontentloaded', timeout: 30000}); | ||
//Wait for page to render. | ||
//Increase or decrease wait time based on endpoint being monitored. | ||
await page.waitFor(15000); | ||
// This will take a screenshot that will be included in test output artifacts | ||
await synthetics.takeScreenshot('loaded', 'loaded'); | ||
let pageTitle = await page.title(); | ||
log.info('Page title: ' + pageTitle); | ||
if (response.status() !== 200) { | ||
throw "Failed to load page!"; | ||
} | ||
}; | ||
|
||
exports.handler = async () => { | ||
return await pageLoadBlueprint(); | ||
}; | ||
``` | ||
|
||
> **Note:** The function **must** be called `handler`. | ||
The canary will automatically produce a CloudWatch Dashboard: | ||
|
||
![UI Screenshot](images/ui-screenshot.png) | ||
|
||
The Canary code will be executed in a lambda function created by Synthetics on your behalf. The Lambda function includes a custom [runtime](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch_Synthetics_Canaries_Library.html) provided by Synthetics. The provided runtime includes a variety of handy tools such as [Puppeteer](https://www.npmjs.com/package/puppeteer-core) and Chromium. To learn more about Synthetics capabilities, check out the [docs](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch_Synthetics_Canaries.html). | ||
|
||
### Configuring the Canary Script | ||
|
||
To configure the script the canary executes, use the `test` property. The `test` property accepts a `Test` instance that can be initialized by the `Test` class static methods. Currently, the only implemented method is `Test.custom()`, which allows you to bring your own code. In the future, other methods will be added. `Test.custom()` accepts `code` and `handler` properties -- both are required by Synthetics to create a lambda function on your behalf. | ||
|
||
The `synthetics.Code` class exposes static methods to bundle your code artifacts: | ||
|
||
- `code.fromInline(code)` - specify an inline script. | ||
- `code.fromAsset(path)` - specify a .zip file or a directory in the local filesystem which will be zipped and uploaded to S3 on deployment. See the above Note for directory structure. | ||
- `code.fromBucket(bucket, key[, objectVersion])` - specify an S3 object that contains the .zip file of your runtime code. See the above Note for directory structure. | ||
|
||
Using the `Code` class static initializers: | ||
|
||
```ts | ||
// To supply the code inline: | ||
const canary = new Canary(this, 'MyCanary', { | ||
test: Test.custom({ | ||
code: Code.fromInline('/* Synthetics handler code */'), | ||
handler: 'index.handler', // must be 'index.handler' | ||
}), | ||
}); | ||
|
||
// To supply the code from your local filesystem: | ||
const canary = new Canary(this, 'MyCanary', { | ||
test: Test.custom({ | ||
code: Code.fromAsset(path.join(__dirname, 'canary')), | ||
handler: 'index.handler', // must end with '.handler' | ||
}), | ||
}); | ||
|
||
// To supply the code from a S3 bucket: | ||
const canary = new Canary(this, 'MyCanary', { | ||
test: Test.custom({ | ||
code: Code.fromBucket(bucket, 'canary.zip'), | ||
handler: 'index.handler', // must end with '.handler' | ||
}), | ||
}); | ||
``` | ||
|
||
> **Note:** For `code.fromAsset()` and `code.fromBucket()`, the canary resource requires the following folder structure: | ||
>``` | ||
>canary/ | ||
>├── nodejs/ | ||
> ├── node_modules/ | ||
> ├── <filename>.js | ||
>``` | ||
> See Synthetics [docs](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch_Synthetics_Canaries_WritingCanary.html). | ||
### Alarms | ||
You can configure a CloudWatch Alarm on a canary metric. Metrics are emitted by CloudWatch automatically and can be accessed by the following APIs: | ||
- `canary.metricSuccessPercent()` - percentage of successful canary runs over a given time | ||
- `canary.metricDuration()` - how much time each canary run takes, in seconds. | ||
- `canary.metricFailed()` - number of failed canary runs over a given time | ||
Create an alarm that tracks the canary metric: | ||
```ts | ||
new cloudwatch.Alarm(this, 'CanaryAlarm', { | ||
metric: canary.metricSuccessPercent(), | ||
evaluationPeriods: 2, | ||
threshold: 90, | ||
comparisonOperator: cloudwatch.ComparisonOperator.LESS_THAN_THRESHOLD, | ||
}); | ||
``` | ||
### Future Work | ||
|
||
- Add blueprints to the Test class [#9613](https://github.com/aws/aws-cdk/issues/9613#issue-677134857). |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Oops, something went wrong.