diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-synthetics/test/integ.canary-resources-to-replicate-tags.js.snapshot/SyntheticsCanaryResourcesToReplicateTagsDefaultTestDeployAssertF883002A.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-synthetics/test/integ.canary-resources-to-replicate-tags.js.snapshot/SyntheticsCanaryResourcesToReplicateTagsDefaultTestDeployAssertF883002A.assets.json new file mode 100644 index 0000000000000..e63a80b4e451d --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-synthetics/test/integ.canary-resources-to-replicate-tags.js.snapshot/SyntheticsCanaryResourcesToReplicateTagsDefaultTestDeployAssertF883002A.assets.json @@ -0,0 +1,20 @@ +{ + "version": "44.0.0", + "files": { + "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { + "displayName": "SyntheticsCanaryResourcesToReplicateTagsDefaultTestDeployAssertF883002A Template", + "source": { + "path": "SyntheticsCanaryResourcesToReplicateTagsDefaultTestDeployAssertF883002A.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + } + }, + "dockerImages": {} +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-synthetics/test/integ.canary-resources-to-replicate-tags.js.snapshot/SyntheticsCanaryResourcesToReplicateTagsDefaultTestDeployAssertF883002A.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-synthetics/test/integ.canary-resources-to-replicate-tags.js.snapshot/SyntheticsCanaryResourcesToReplicateTagsDefaultTestDeployAssertF883002A.template.json new file mode 100644 index 0000000000000..ad9d0fb73d1dd --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-synthetics/test/integ.canary-resources-to-replicate-tags.js.snapshot/SyntheticsCanaryResourcesToReplicateTagsDefaultTestDeployAssertF883002A.template.json @@ -0,0 +1,36 @@ +{ + "Parameters": { + "BootstrapVersion": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/cdk-bootstrap/hnb659fds/version", + "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]" + } + }, + "Rules": { + "CheckBootstrapVersion": { + "Assertions": [ + { + "Assert": { + "Fn::Not": [ + { + "Fn::Contains": [ + [ + "1", + "2", + "3", + "4", + "5" + ], + { + "Ref": "BootstrapVersion" + } + ] + } + ] + }, + "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI." + } + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-synthetics/test/integ.canary-resources-to-replicate-tags.js.snapshot/SyntheticsCanaryResourcesToReplicateTagsStack.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-synthetics/test/integ.canary-resources-to-replicate-tags.js.snapshot/SyntheticsCanaryResourcesToReplicateTagsStack.assets.json new file mode 100644 index 0000000000000..12b6e439c740c --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-synthetics/test/integ.canary-resources-to-replicate-tags.js.snapshot/SyntheticsCanaryResourcesToReplicateTagsStack.assets.json @@ -0,0 +1,34 @@ +{ + "version": "44.0.0", + "files": { + "5178413cfe8db00b2d5dcfa9be417e934c64601d0da3031d88c145c8293bc27f": { + "displayName": "TagReplicationCanary/Code", + "source": { + "path": "asset.5178413cfe8db00b2d5dcfa9be417e934c64601d0da3031d88c145c8293bc27f", + "packaging": "zip" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "5178413cfe8db00b2d5dcfa9be417e934c64601d0da3031d88c145c8293bc27f.zip", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + }, + "05afbffbd3fd4bafcca6e1f1f35525efe38124e6892f294ec7421e1d97072304": { + "displayName": "SyntheticsCanaryResourcesToReplicateTagsStack Template", + "source": { + "path": "SyntheticsCanaryResourcesToReplicateTagsStack.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "05afbffbd3fd4bafcca6e1f1f35525efe38124e6892f294ec7421e1d97072304.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + } + }, + "dockerImages": {} +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-synthetics/test/integ.canary-resources-to-replicate-tags.js.snapshot/SyntheticsCanaryResourcesToReplicateTagsStack.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-synthetics/test/integ.canary-resources-to-replicate-tags.js.snapshot/SyntheticsCanaryResourcesToReplicateTagsStack.template.json new file mode 100644 index 0000000000000..63dba8cbccf50 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-synthetics/test/integ.canary-resources-to-replicate-tags.js.snapshot/SyntheticsCanaryResourcesToReplicateTagsStack.template.json @@ -0,0 +1,284 @@ +{ + "Resources": { + "TagReplicationCanaryArtifactsBucket66A919F9": { + "Type": "AWS::S3::Bucket", + "Properties": { + "BucketEncryption": { + "ServerSideEncryptionConfiguration": [ + { + "ServerSideEncryptionByDefault": { + "SSEAlgorithm": "aws:kms" + } + } + ] + }, + "Tags": [ + { + "Key": "Environment", + "Value": "test" + }, + { + "Key": "Owner", + "Value": "cdk-team" + }, + { + "Key": "Project", + "Value": "synthetics-tag-replication" + } + ] + }, + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" + }, + "TagReplicationCanaryArtifactsBucketPolicyCFD9E77B": { + "Type": "AWS::S3::BucketPolicy", + "Properties": { + "Bucket": { + "Ref": "TagReplicationCanaryArtifactsBucket66A919F9" + }, + "PolicyDocument": { + "Statement": [ + { + "Action": "s3:*", + "Condition": { + "Bool": { + "aws:SecureTransport": "false" + } + }, + "Effect": "Deny", + "Principal": { + "AWS": "*" + }, + "Resource": [ + { + "Fn::GetAtt": [ + "TagReplicationCanaryArtifactsBucket66A919F9", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "TagReplicationCanaryArtifactsBucket66A919F9", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + } + } + }, + "TagReplicationCanaryServiceRoleE1E5A2B6": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "Policies": [ + { + "PolicyDocument": { + "Statement": [ + { + "Action": "s3:ListAllMyBuckets", + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": "s3:GetBucketLocation", + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "TagReplicationCanaryArtifactsBucket66A919F9", + "Arn" + ] + } + }, + { + "Action": "s3:PutObject", + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "TagReplicationCanaryArtifactsBucket66A919F9", + "Arn" + ] + }, + "/*" + ] + ] + } + }, + { + "Action": "cloudwatch:PutMetricData", + "Condition": { + "StringEquals": { + "cloudwatch:namespace": "CloudWatchSynthetics" + } + }, + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":logs:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":log-group:/aws/lambda/cwsyn-*" + ] + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "canaryPolicy" + } + ], + "Tags": [ + { + "Key": "Environment", + "Value": "test" + }, + { + "Key": "Owner", + "Value": "cdk-team" + }, + { + "Key": "Project", + "Value": "synthetics-tag-replication" + } + ] + } + }, + "TagReplicationCanary4B22C124": { + "Type": "AWS::Synthetics::Canary", + "Properties": { + "ArtifactS3Location": { + "Fn::Join": [ + "", + [ + "s3://", + { + "Ref": "TagReplicationCanaryArtifactsBucket66A919F9" + } + ] + ] + }, + "Code": { + "Handler": "canary.handler", + "S3Bucket": { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "S3Key": "5178413cfe8db00b2d5dcfa9be417e934c64601d0da3031d88c145c8293bc27f.zip" + }, + "ExecutionRoleArn": { + "Fn::GetAtt": [ + "TagReplicationCanaryServiceRoleE1E5A2B6", + "Arn" + ] + }, + "Name": "tag-replication", + "ResourcesToReplicateTags": [ + "lambda-function" + ], + "RunConfig": { + "MemoryInMB": 1024, + "TimeoutInSeconds": 180 + }, + "RuntimeVersion": "syn-nodejs-puppeteer-7.0", + "Schedule": { + "DurationInSeconds": "0", + "Expression": "rate(5 minutes)" + }, + "StartCanaryAfterCreation": true, + "Tags": [ + { + "Key": "Environment", + "Value": "test" + }, + { + "Key": "Owner", + "Value": "cdk-team" + }, + { + "Key": "Project", + "Value": "synthetics-tag-replication" + } + ] + } + } + }, + "Parameters": { + "BootstrapVersion": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/cdk-bootstrap/hnb659fds/version", + "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]" + } + }, + "Rules": { + "CheckBootstrapVersion": { + "Assertions": [ + { + "Assert": { + "Fn::Not": [ + { + "Fn::Contains": [ + [ + "1", + "2", + "3", + "4", + "5" + ], + { + "Ref": "BootstrapVersion" + } + ] + } + ] + }, + "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI." + } + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-synthetics/test/integ.canary-resources-to-replicate-tags.js.snapshot/asset.5178413cfe8db00b2d5dcfa9be417e934c64601d0da3031d88c145c8293bc27f/canary.mjs b/packages/@aws-cdk-testing/framework-integ/test/aws-synthetics/test/integ.canary-resources-to-replicate-tags.js.snapshot/asset.5178413cfe8db00b2d5dcfa9be417e934c64601d0da3031d88c145c8293bc27f/canary.mjs new file mode 100644 index 0000000000000..eb6bd4e9b823d --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-synthetics/test/integ.canary-resources-to-replicate-tags.js.snapshot/asset.5178413cfe8db00b2d5dcfa9be417e934c64601d0da3031d88c145c8293bc27f/canary.mjs @@ -0,0 +1,87 @@ +import { URL } from 'url'; +import { synthetics } from '@amzn/synthetics-playwright'; + +const loadBlueprints = async function () { + const urls = [process.env.URL]; + + const browser = await synthetics.launch(); + const browserContext = await browser.newContext(); + let page = await synthetics.newPage(browserContext); + + for (const url of urls) { + await loadUrl(page, url); + } + + // Ensure browser is closed + await synthetics.close(); +}; + +// Reset the page in-between +const resetPage = async function(page) { + try { + // Set page.goto timeout to 30 seconds, adjust as needed + // See https://playwright.dev/docs/api/class-page for page.goto options + await page.goto('about:blank', { waitUntil: 'load', timeout: 30000 }); + } catch (e) { + console.error('Unable to open a blank page. ', e); + } +}; + +const loadUrl = async function (page, url) { + let stepName = null; + let domcontentloaded = false; + + try { + stepName = new URL(url).hostname; + } catch (e) { + const errorString = `Error parsing url: ${url}. ${e}`; + log.error(errorString); + /* If we fail to parse the URL, don't emit a metric with a stepName based on it. + It may not be a legal CloudWatch metric dimension name and we may not have an alarms + setup on the malformed URL stepName. Instead, fail this step which will + show up in the logs and will fail the overall canary and alarm on the overall canary + success rate. + */ + throw e; + }; + + await synthetics.executeStep(stepName, async function () { + try { + /* You can customize the wait condition here. + 'domcontentloaded' - consider operation to be finished when the DOMContentLoaded event is fired. + 'load' - consider operation to be finished when the load event is fired. + 'networkidle' - DISCOURAGED consider operation to be finished when there are no network connections for at least 500 ms. Don't use this method for testing, rely on web assertions to assess readiness instead. + 'commit' - consider operation to be finished when network response is received and the document started loading. + + Set page.goto timeout to 30 seconds, adjust as needed + See https://playwright.dev/docs/api/class-page for page.goto options + */ + const response = await page.goto(url, { waitUntil: 'load', timeout: 30000 }); + if (response) { + domcontentloaded = true; + const status = response.status(); + console.log(`Response status: ${status}`); + + // If the response status code is not a 2xx success code + if (status < 200 || status > 299) { + console.error(`Failed to load url: ${url}, status code: ${status}`); + throw new Error('Failed'); + } + } else { + console.error(`No response returned for url: ${url}`); + throw new Error(logNoResponseString); + } + } catch (e) { + const errorString = `Error navigating to url: ${url}. ${e}`; + console.error(errorString); + throw e; + } + }); + + // Reset page + await resetPage(page); +}; + +export const handler = async (event, context) => { + return await loadBlueprints(); +}; \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-synthetics/test/integ.canary-resources-to-replicate-tags.js.snapshot/asset.5178413cfe8db00b2d5dcfa9be417e934c64601d0da3031d88c145c8293bc27f/nodejs/node_modules/canary.js b/packages/@aws-cdk-testing/framework-integ/test/aws-synthetics/test/integ.canary-resources-to-replicate-tags.js.snapshot/asset.5178413cfe8db00b2d5dcfa9be417e934c64601d0da3031d88c145c8293bc27f/nodejs/node_modules/canary.js new file mode 100644 index 0000000000000..d7936811fd8c1 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-synthetics/test/integ.canary-resources-to-replicate-tags.js.snapshot/asset.5178413cfe8db00b2d5dcfa9be417e934c64601d0da3031d88c145c8293bc27f/nodejs/node_modules/canary.js @@ -0,0 +1,52 @@ +var synthetics = require('Synthetics'); +const log = require('SyntheticsLogger'); +const https = require('https'); +const http = require('http'); + +const apiCanaryBlueprint = async function () { + const postData = ""; + + const verifyRequest = async function (requestOption) { + return new Promise((resolve, reject) => { + log.info("Making request with options: " + JSON.stringify(requestOption)); + let req + if (requestOption.protocol === 'https:') { + req = https.request(requestOption); + } else { + req = http.request(requestOption); + } + req.on('response', (res) => { + log.info(`Status Code: ${res.statusCode}`) + log.info(`Response Headers: ${JSON.stringify(res.headers)}`) + if (res.statusCode !== 200) { + reject("Failed: " + requestOption.pathname); + } + res.on('data', (d) => { + log.info("Response: " + d); + }); + res.on('end', () => { + resolve(); + }) + }); + + req.on('error', (error) => { + reject(error); + }); + + if (postData) { + req.write(postData); + } + req.end(); + }); + } + + const headers = {} + headers['User-Agent'] = [synthetics.getCanaryUserAgentString(), headers['User-Agent']].join(' '); + const requestOptions = new URL(process.env.URL); + requestOptions['headers'] = headers; + await verifyRequest(requestOptions); +}; + +exports.handler = async () => { + return await apiCanaryBlueprint(); +}; \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-synthetics/test/integ.canary-resources-to-replicate-tags.js.snapshot/asset.5178413cfe8db00b2d5dcfa9be417e934c64601d0da3031d88c145c8293bc27f/nodejs/node_modules/folder/canary.js b/packages/@aws-cdk-testing/framework-integ/test/aws-synthetics/test/integ.canary-resources-to-replicate-tags.js.snapshot/asset.5178413cfe8db00b2d5dcfa9be417e934c64601d0da3031d88c145c8293bc27f/nodejs/node_modules/folder/canary.js new file mode 100644 index 0000000000000..2ee399fbc633f --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-synthetics/test/integ.canary-resources-to-replicate-tags.js.snapshot/asset.5178413cfe8db00b2d5dcfa9be417e934c64601d0da3031d88c145c8293bc27f/nodejs/node_modules/folder/canary.js @@ -0,0 +1,52 @@ +var synthetics = require('Synthetics'); +const log = require('SyntheticsLogger'); +const https = require('https'); +const http = require('http'); + +const apiCanaryBlueprint = async function () { + const postData = ""; + + const verifyRequest = async function (requestOption) { + return new Promise((resolve, reject) => { + log.info("Making request with options: " + JSON.stringify(requestOption)); + let req + if (requestOption.protocol === 'https:') { + req = https.request(requestOption); + } else { + req = http.request(requestOption); + } + req.on('response', (res) => { + log.info(`Status Code: ${res.statusCode}`) + log.info(`Response Headers: ${JSON.stringify(res.headers)}`) + if (res.statusCode !== 200) { + reject("Failed: " + requestOption.pathname); + } + res.on('data', (d) => { + log.info("Response: " + d); + }); + res.on('end', () => { + resolve(); + }) + }); + + req.on('error', (error) => { + reject(error); + }); + + if (postData) { + req.write(postData); + } + req.end(); + }); + } + + const headers = {} + headers['User-Agent'] = [synthetics.getCanaryUserAgentString(), headers['User-Agent']].join(' '); + const requestOptions = new URL(process.env.URL); + requestOptions['headers'] = headers; + await verifyRequest(requestOptions); +}; + +exports.functionName = async () => { + return await apiCanaryBlueprint(); +}; \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-synthetics/test/integ.canary-resources-to-replicate-tags.js.snapshot/asset.5178413cfe8db00b2d5dcfa9be417e934c64601d0da3031d88c145c8293bc27f/playwright/canary.mjs b/packages/@aws-cdk-testing/framework-integ/test/aws-synthetics/test/integ.canary-resources-to-replicate-tags.js.snapshot/asset.5178413cfe8db00b2d5dcfa9be417e934c64601d0da3031d88c145c8293bc27f/playwright/canary.mjs new file mode 100644 index 0000000000000..eb6bd4e9b823d --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-synthetics/test/integ.canary-resources-to-replicate-tags.js.snapshot/asset.5178413cfe8db00b2d5dcfa9be417e934c64601d0da3031d88c145c8293bc27f/playwright/canary.mjs @@ -0,0 +1,87 @@ +import { URL } from 'url'; +import { synthetics } from '@amzn/synthetics-playwright'; + +const loadBlueprints = async function () { + const urls = [process.env.URL]; + + const browser = await synthetics.launch(); + const browserContext = await browser.newContext(); + let page = await synthetics.newPage(browserContext); + + for (const url of urls) { + await loadUrl(page, url); + } + + // Ensure browser is closed + await synthetics.close(); +}; + +// Reset the page in-between +const resetPage = async function(page) { + try { + // Set page.goto timeout to 30 seconds, adjust as needed + // See https://playwright.dev/docs/api/class-page for page.goto options + await page.goto('about:blank', { waitUntil: 'load', timeout: 30000 }); + } catch (e) { + console.error('Unable to open a blank page. ', e); + } +}; + +const loadUrl = async function (page, url) { + let stepName = null; + let domcontentloaded = false; + + try { + stepName = new URL(url).hostname; + } catch (e) { + const errorString = `Error parsing url: ${url}. ${e}`; + log.error(errorString); + /* If we fail to parse the URL, don't emit a metric with a stepName based on it. + It may not be a legal CloudWatch metric dimension name and we may not have an alarms + setup on the malformed URL stepName. Instead, fail this step which will + show up in the logs and will fail the overall canary and alarm on the overall canary + success rate. + */ + throw e; + }; + + await synthetics.executeStep(stepName, async function () { + try { + /* You can customize the wait condition here. + 'domcontentloaded' - consider operation to be finished when the DOMContentLoaded event is fired. + 'load' - consider operation to be finished when the load event is fired. + 'networkidle' - DISCOURAGED consider operation to be finished when there are no network connections for at least 500 ms. Don't use this method for testing, rely on web assertions to assess readiness instead. + 'commit' - consider operation to be finished when network response is received and the document started loading. + + Set page.goto timeout to 30 seconds, adjust as needed + See https://playwright.dev/docs/api/class-page for page.goto options + */ + const response = await page.goto(url, { waitUntil: 'load', timeout: 30000 }); + if (response) { + domcontentloaded = true; + const status = response.status(); + console.log(`Response status: ${status}`); + + // If the response status code is not a 2xx success code + if (status < 200 || status > 299) { + console.error(`Failed to load url: ${url}, status code: ${status}`); + throw new Error('Failed'); + } + } else { + console.error(`No response returned for url: ${url}`); + throw new Error(logNoResponseString); + } + } catch (e) { + const errorString = `Error navigating to url: ${url}. ${e}`; + console.error(errorString); + throw e; + } + }); + + // Reset page + await resetPage(page); +}; + +export const handler = async (event, context) => { + return await loadBlueprints(); +}; \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-synthetics/test/integ.canary-resources-to-replicate-tags.js.snapshot/asset.5178413cfe8db00b2d5dcfa9be417e934c64601d0da3031d88c145c8293bc27f/python/canary.py b/packages/@aws-cdk-testing/framework-integ/test/aws-synthetics/test/integ.canary-resources-to-replicate-tags.js.snapshot/asset.5178413cfe8db00b2d5dcfa9be417e934c64601d0da3031d88c145c8293bc27f/python/canary.py new file mode 100644 index 0000000000000..fac8b8004a7a7 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-synthetics/test/integ.canary-resources-to-replicate-tags.js.snapshot/asset.5178413cfe8db00b2d5dcfa9be417e934c64601d0da3031d88c145c8293bc27f/python/canary.py @@ -0,0 +1,62 @@ +# This example comes from the AWS Synthetics service console "API canary" blueprint + +import os +import json +import http.client +import urllib.parse +from aws_synthetics.selenium import synthetics_webdriver as syn_webdriver +from aws_synthetics.common import synthetics_logger as logger + + +def verify_request(method, url, post_data=None, headers={}): + parsed_url = urllib.parse.urlparse(url) + user_agent = str(syn_webdriver.get_canary_user_agent_string()) + if "User-Agent" in headers: + headers["User-Agent"] = " ".join([user_agent, headers["User-Agent"]]) + else: + headers["User-Agent"] = "{}".format(user_agent) + + logger.info("Making request with Method: '%s' URL: %s: Data: %s Headers: %s" % ( + method, url, json.dumps(post_data), json.dumps(headers))) + + if parsed_url.scheme == "https": + conn = http.client.HTTPSConnection(parsed_url.hostname, parsed_url.port) + else: + conn = http.client.HTTPConnection(parsed_url.hostname, parsed_url.port) + + conn.request(method, url, post_data, headers) + response = conn.getresponse() + logger.info("Status Code: %s " % response.status) + logger.info("Response Headers: %s" % json.dumps(response.headers.as_string())) + + if not response.status or response.status < 200 or response.status > 299: + try: + logger.error("Response: %s" % response.read().decode()) + finally: + if response.reason: + conn.close() + raise Exception("Failed: %s" % response.reason) + else: + conn.close() + raise Exception("Failed with status code: %s" % response.status) + + logger.info("Response: %s" % response.read().decode()) + logger.info("HTTP request successfully executed") + conn.close() + + +def main(): + + url = os.environ['URL'] + method = 'GET' + postData = "" + headers = {} + + verify_request(method, url, None, headers) + + logger.info("Canary successfully executed") + + +def handler(event, context): + logger.info("Selenium Python API canary") + main() \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-synthetics/test/integ.canary-resources-to-replicate-tags.js.snapshot/cdk.out b/packages/@aws-cdk-testing/framework-integ/test/aws-synthetics/test/integ.canary-resources-to-replicate-tags.js.snapshot/cdk.out new file mode 100644 index 0000000000000..b3a26d44a5f73 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-synthetics/test/integ.canary-resources-to-replicate-tags.js.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"44.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-synthetics/test/integ.canary-resources-to-replicate-tags.js.snapshot/integ.json b/packages/@aws-cdk-testing/framework-integ/test/aws-synthetics/test/integ.canary-resources-to-replicate-tags.js.snapshot/integ.json new file mode 100644 index 0000000000000..d0d696a4b8c7f --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-synthetics/test/integ.canary-resources-to-replicate-tags.js.snapshot/integ.json @@ -0,0 +1,13 @@ +{ + "version": "44.0.0", + "testCases": { + "SyntheticsCanaryResourcesToReplicateTags/DefaultTest": { + "stacks": [ + "SyntheticsCanaryResourcesToReplicateTagsStack" + ], + "assertionStack": "SyntheticsCanaryResourcesToReplicateTags/DefaultTest/DeployAssert", + "assertionStackName": "SyntheticsCanaryResourcesToReplicateTagsDefaultTestDeployAssertF883002A" + } + }, + "minimumCliVersion": "2.1018.0" +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-synthetics/test/integ.canary-resources-to-replicate-tags.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-synthetics/test/integ.canary-resources-to-replicate-tags.js.snapshot/manifest.json new file mode 100644 index 0000000000000..96a7fa9f07bf3 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-synthetics/test/integ.canary-resources-to-replicate-tags.js.snapshot/manifest.json @@ -0,0 +1,181 @@ +{ + "version": "44.0.0", + "artifacts": { + "SyntheticsCanaryResourcesToReplicateTagsStack.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "SyntheticsCanaryResourcesToReplicateTagsStack.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "SyntheticsCanaryResourcesToReplicateTagsStack": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "SyntheticsCanaryResourcesToReplicateTagsStack.template.json", + "terminationProtection": false, + "validateOnSynth": false, + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", + "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/05afbffbd3fd4bafcca6e1f1f35525efe38124e6892f294ec7421e1d97072304.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "SyntheticsCanaryResourcesToReplicateTagsStack.assets" + ], + "lookupRole": { + "arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-${AWS::Region}", + "requiresBootstrapStackVersion": 8, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "dependencies": [ + "SyntheticsCanaryResourcesToReplicateTagsStack.assets" + ], + "metadata": { + "/SyntheticsCanaryResourcesToReplicateTagsStack/TagReplicationCanary": [ + { + "type": "aws:cdk:analytics:construct", + "data": { + "canaryName": "*", + "runtime": "*", + "test": "*", + "memory": "*", + "timeout": "*" + } + } + ], + "/SyntheticsCanaryResourcesToReplicateTagsStack/TagReplicationCanary/ArtifactsBucket": [ + { + "type": "aws:cdk:analytics:construct", + "data": { + "encryption": "KMS_MANAGED", + "enforceSSL": true, + "lifecycleRules": "*" + } + } + ], + "/SyntheticsCanaryResourcesToReplicateTagsStack/TagReplicationCanary/ArtifactsBucket/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "TagReplicationCanaryArtifactsBucket66A919F9" + } + ], + "/SyntheticsCanaryResourcesToReplicateTagsStack/TagReplicationCanary/ArtifactsBucket/Policy": [ + { + "type": "aws:cdk:analytics:construct", + "data": { + "bucket": "*" + } + } + ], + "/SyntheticsCanaryResourcesToReplicateTagsStack/TagReplicationCanary/ArtifactsBucket/Policy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "TagReplicationCanaryArtifactsBucketPolicyCFD9E77B" + } + ], + "/SyntheticsCanaryResourcesToReplicateTagsStack/TagReplicationCanary/ServiceRole": [ + { + "type": "aws:cdk:analytics:construct", + "data": { + "assumedBy": { + "principalAccount": "*", + "assumeRoleAction": "*" + }, + "inlinePolicies": "*", + "managedPolicies": [] + } + } + ], + "/SyntheticsCanaryResourcesToReplicateTagsStack/TagReplicationCanary/ServiceRole/ImportServiceRole": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + } + ], + "/SyntheticsCanaryResourcesToReplicateTagsStack/TagReplicationCanary/ServiceRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "TagReplicationCanaryServiceRoleE1E5A2B6" + } + ], + "/SyntheticsCanaryResourcesToReplicateTagsStack/TagReplicationCanary/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "TagReplicationCanary4B22C124" + } + ], + "/SyntheticsCanaryResourcesToReplicateTagsStack/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/SyntheticsCanaryResourcesToReplicateTagsStack/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "SyntheticsCanaryResourcesToReplicateTagsStack" + }, + "SyntheticsCanaryResourcesToReplicateTagsDefaultTestDeployAssertF883002A.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "SyntheticsCanaryResourcesToReplicateTagsDefaultTestDeployAssertF883002A.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "SyntheticsCanaryResourcesToReplicateTagsDefaultTestDeployAssertF883002A": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "SyntheticsCanaryResourcesToReplicateTagsDefaultTestDeployAssertF883002A.template.json", + "terminationProtection": false, + "validateOnSynth": false, + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", + "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "SyntheticsCanaryResourcesToReplicateTagsDefaultTestDeployAssertF883002A.assets" + ], + "lookupRole": { + "arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-${AWS::Region}", + "requiresBootstrapStackVersion": 8, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "dependencies": [ + "SyntheticsCanaryResourcesToReplicateTagsDefaultTestDeployAssertF883002A.assets" + ], + "metadata": { + "/SyntheticsCanaryResourcesToReplicateTags/DefaultTest/DeployAssert/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/SyntheticsCanaryResourcesToReplicateTags/DefaultTest/DeployAssert/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "SyntheticsCanaryResourcesToReplicateTags/DefaultTest/DeployAssert" + }, + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } + } + }, + "minimumCliVersion": "2.1018.0" +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-synthetics/test/integ.canary-resources-to-replicate-tags.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/aws-synthetics/test/integ.canary-resources-to-replicate-tags.js.snapshot/tree.json new file mode 100644 index 0000000000000..a7e6f8f68bf09 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-synthetics/test/integ.canary-resources-to-replicate-tags.js.snapshot/tree.json @@ -0,0 +1 @@ +{"version":"tree-0.1","tree":{"id":"App","path":"","constructInfo":{"fqn":"aws-cdk-lib.App","version":"0.0.0"},"children":{"SyntheticsCanaryResourcesToReplicateTagsStack":{"id":"SyntheticsCanaryResourcesToReplicateTagsStack","path":"SyntheticsCanaryResourcesToReplicateTagsStack","constructInfo":{"fqn":"aws-cdk-lib.Stack","version":"0.0.0"},"children":{"TagReplicationCanary":{"id":"TagReplicationCanary","path":"SyntheticsCanaryResourcesToReplicateTagsStack/TagReplicationCanary","constructInfo":{"fqn":"aws-cdk-lib.aws_synthetics.Canary","version":"0.0.0","metadata":[{"canaryName":"*","runtime":"*","test":"*","memory":"*","timeout":"*"}]},"children":{"ArtifactsBucket":{"id":"ArtifactsBucket","path":"SyntheticsCanaryResourcesToReplicateTagsStack/TagReplicationCanary/ArtifactsBucket","constructInfo":{"fqn":"aws-cdk-lib.aws_s3.Bucket","version":"0.0.0","metadata":[{"encryption":"KMS_MANAGED","enforceSSL":true,"lifecycleRules":"*"}]},"children":{"Resource":{"id":"Resource","path":"SyntheticsCanaryResourcesToReplicateTagsStack/TagReplicationCanary/ArtifactsBucket/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_s3.CfnBucket","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::S3::Bucket","aws:cdk:cloudformation:props":{"bucketEncryption":{"serverSideEncryptionConfiguration":[{"serverSideEncryptionByDefault":{"sseAlgorithm":"aws:kms"}}]},"tags":[{"key":"Environment","value":"test"},{"key":"Owner","value":"cdk-team"},{"key":"Project","value":"synthetics-tag-replication"}]}}},"Policy":{"id":"Policy","path":"SyntheticsCanaryResourcesToReplicateTagsStack/TagReplicationCanary/ArtifactsBucket/Policy","constructInfo":{"fqn":"aws-cdk-lib.aws_s3.BucketPolicy","version":"0.0.0","metadata":[{"bucket":"*"}]},"children":{"Resource":{"id":"Resource","path":"SyntheticsCanaryResourcesToReplicateTagsStack/TagReplicationCanary/ArtifactsBucket/Policy/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_s3.CfnBucketPolicy","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::S3::BucketPolicy","aws:cdk:cloudformation:props":{"bucket":{"Ref":"TagReplicationCanaryArtifactsBucket66A919F9"},"policyDocument":{"Statement":[{"Action":"s3:*","Condition":{"Bool":{"aws:SecureTransport":"false"}},"Effect":"Deny","Principal":{"AWS":"*"},"Resource":[{"Fn::GetAtt":["TagReplicationCanaryArtifactsBucket66A919F9","Arn"]},{"Fn::Join":["",[{"Fn::GetAtt":["TagReplicationCanaryArtifactsBucket66A919F9","Arn"]},"/*"]]}]}],"Version":"2012-10-17"}}}}}}}},"ServiceRole":{"id":"ServiceRole","path":"SyntheticsCanaryResourcesToReplicateTagsStack/TagReplicationCanary/ServiceRole","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.Role","version":"0.0.0","metadata":[{"assumedBy":{"principalAccount":"*","assumeRoleAction":"*"},"inlinePolicies":"*","managedPolicies":[]}]},"children":{"ImportServiceRole":{"id":"ImportServiceRole","path":"SyntheticsCanaryResourcesToReplicateTagsStack/TagReplicationCanary/ServiceRole/ImportServiceRole","constructInfo":{"fqn":"aws-cdk-lib.Resource","version":"0.0.0","metadata":["*"]}},"Resource":{"id":"Resource","path":"SyntheticsCanaryResourcesToReplicateTagsStack/TagReplicationCanary/ServiceRole/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.CfnRole","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Role","aws:cdk:cloudformation:props":{"assumeRolePolicyDocument":{"Statement":[{"Action":"sts:AssumeRole","Effect":"Allow","Principal":{"Service":"lambda.amazonaws.com"}}],"Version":"2012-10-17"},"policies":[{"policyName":"canaryPolicy","policyDocument":{"Statement":[{"Action":"s3:ListAllMyBuckets","Effect":"Allow","Resource":"*"},{"Action":"s3:GetBucketLocation","Effect":"Allow","Resource":{"Fn::GetAtt":["TagReplicationCanaryArtifactsBucket66A919F9","Arn"]}},{"Action":"s3:PutObject","Effect":"Allow","Resource":{"Fn::Join":["",[{"Fn::GetAtt":["TagReplicationCanaryArtifactsBucket66A919F9","Arn"]},"/*"]]}},{"Action":"cloudwatch:PutMetricData","Condition":{"StringEquals":{"cloudwatch:namespace":"CloudWatchSynthetics"}},"Effect":"Allow","Resource":"*"},{"Action":["logs:CreateLogGroup","logs:CreateLogStream","logs:PutLogEvents"],"Effect":"Allow","Resource":{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":logs:",{"Ref":"AWS::Region"},":",{"Ref":"AWS::AccountId"},":log-group:/aws/lambda/cwsyn-*"]]}}],"Version":"2012-10-17"}}],"tags":[{"key":"Environment","value":"test"},{"key":"Owner","value":"cdk-team"},{"key":"Project","value":"synthetics-tag-replication"}]}}}}},"Code":{"id":"Code","path":"SyntheticsCanaryResourcesToReplicateTagsStack/TagReplicationCanary/Code","constructInfo":{"fqn":"aws-cdk-lib.aws_s3_assets.Asset","version":"0.0.0"},"children":{"Stage":{"id":"Stage","path":"SyntheticsCanaryResourcesToReplicateTagsStack/TagReplicationCanary/Code/Stage","constructInfo":{"fqn":"aws-cdk-lib.AssetStaging","version":"0.0.0"}},"AssetBucket":{"id":"AssetBucket","path":"SyntheticsCanaryResourcesToReplicateTagsStack/TagReplicationCanary/Code/AssetBucket","constructInfo":{"fqn":"aws-cdk-lib.aws_s3.BucketBase","version":"0.0.0","metadata":[]}}}},"Resource":{"id":"Resource","path":"SyntheticsCanaryResourcesToReplicateTagsStack/TagReplicationCanary/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_synthetics.CfnCanary","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::Synthetics::Canary","aws:cdk:cloudformation:props":{"artifactS3Location":{"Fn::Join":["",["s3://",{"Ref":"TagReplicationCanaryArtifactsBucket66A919F9"}]]},"code":{"handler":"canary.handler","s3Bucket":{"Fn::Sub":"cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}"},"s3Key":"5178413cfe8db00b2d5dcfa9be417e934c64601d0da3031d88c145c8293bc27f.zip"},"executionRoleArn":{"Fn::GetAtt":["TagReplicationCanaryServiceRoleE1E5A2B6","Arn"]},"name":"tag-replication","resourcesToReplicateTags":["lambda-function"],"runConfig":{"memoryInMb":1024,"timeoutInSeconds":180},"runtimeVersion":"syn-nodejs-puppeteer-7.0","schedule":{"durationInSeconds":"0","expression":"rate(5 minutes)"},"startCanaryAfterCreation":true,"tags":[{"key":"Environment","value":"test"},{"key":"Owner","value":"cdk-team"},{"key":"Project","value":"synthetics-tag-replication"}]}}}}},"BootstrapVersion":{"id":"BootstrapVersion","path":"SyntheticsCanaryResourcesToReplicateTagsStack/BootstrapVersion","constructInfo":{"fqn":"aws-cdk-lib.CfnParameter","version":"0.0.0"}},"CheckBootstrapVersion":{"id":"CheckBootstrapVersion","path":"SyntheticsCanaryResourcesToReplicateTagsStack/CheckBootstrapVersion","constructInfo":{"fqn":"aws-cdk-lib.CfnRule","version":"0.0.0"}}}},"SyntheticsCanaryResourcesToReplicateTags":{"id":"SyntheticsCanaryResourcesToReplicateTags","path":"SyntheticsCanaryResourcesToReplicateTags","constructInfo":{"fqn":"@aws-cdk/integ-tests-alpha.IntegTest","version":"0.0.0"},"children":{"DefaultTest":{"id":"DefaultTest","path":"SyntheticsCanaryResourcesToReplicateTags/DefaultTest","constructInfo":{"fqn":"@aws-cdk/integ-tests-alpha.IntegTestCase","version":"0.0.0"},"children":{"Default":{"id":"Default","path":"SyntheticsCanaryResourcesToReplicateTags/DefaultTest/Default","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"DeployAssert":{"id":"DeployAssert","path":"SyntheticsCanaryResourcesToReplicateTags/DefaultTest/DeployAssert","constructInfo":{"fqn":"aws-cdk-lib.Stack","version":"0.0.0"},"children":{"BootstrapVersion":{"id":"BootstrapVersion","path":"SyntheticsCanaryResourcesToReplicateTags/DefaultTest/DeployAssert/BootstrapVersion","constructInfo":{"fqn":"aws-cdk-lib.CfnParameter","version":"0.0.0"}},"CheckBootstrapVersion":{"id":"CheckBootstrapVersion","path":"SyntheticsCanaryResourcesToReplicateTags/DefaultTest/DeployAssert/CheckBootstrapVersion","constructInfo":{"fqn":"aws-cdk-lib.CfnRule","version":"0.0.0"}}}}}}}},"Tree":{"id":"Tree","path":"Tree","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}}}}} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-synthetics/test/integ.canary-resources-to-replicate-tags.ts b/packages/@aws-cdk-testing/framework-integ/test/aws-synthetics/test/integ.canary-resources-to-replicate-tags.ts new file mode 100644 index 0000000000000..d44c4cc6f8e0d --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-synthetics/test/integ.canary-resources-to-replicate-tags.ts @@ -0,0 +1,36 @@ +import * as path from 'node:path'; +import { App, Duration, Size, Stack, StackProps, Tags } from 'aws-cdk-lib/core'; +import { IntegTest } from '@aws-cdk/integ-tests-alpha'; +import { Construct } from 'constructs'; +import * as synthetics from 'aws-cdk-lib/aws-synthetics'; + +class TestStack extends Stack { + public canary: synthetics.Canary; + + constructor(scope: Construct, id: string, props?: StackProps) { + super(scope, id, props); + + this.canary = new synthetics.Canary(this, 'TagReplicationCanary', { + canaryName: 'tag-replication', + runtime: synthetics.Runtime.SYNTHETICS_NODEJS_PUPPETEER_7_0, + test: synthetics.Test.custom({ + handler: 'canary.handler', + code: synthetics.Code.fromAsset(path.join(__dirname, 'canaries')), + }), + memory: Size.mebibytes(1024), + timeout: Duration.minutes(3), + resourcesToReplicateTags: [synthetics.ResourceToReplicateTags.LAMBDA_FUNCTION], + }); + + Tags.of(this.canary).add('Environment', 'test'); + Tags.of(this.canary).add('Owner', 'cdk-team'); + Tags.of(this.canary).add('Project', 'synthetics-tag-replication'); + } +} + +const app = new App(); +const testStack = new TestStack(app, 'SyntheticsCanaryResourcesToReplicateTagsStack'); + +new IntegTest(app, 'SyntheticsCanaryResourcesToReplicateTags', { + testCases: [testStack], +}); diff --git a/packages/aws-cdk-lib/aws-synthetics/README.md b/packages/aws-cdk-lib/aws-synthetics/README.md index 09ffe2642a96f..5b39bf5c15987 100644 --- a/packages/aws-cdk-lib/aws-synthetics/README.md +++ b/packages/aws-cdk-lib/aws-synthetics/README.md @@ -390,3 +390,21 @@ const canary = new synthetics.Canary(this, 'MyCanary', { }); ``` +### Tag replication + +You can configure a canary to replicate its tags to the underlying Lambda function. This is useful when you want the same tags that are applied to the canary to also be applied to the Lambda function that the canary uses. + +```ts +const canary = new synthetics.Canary(this, 'MyCanary', { + schedule: synthetics.Schedule.rate(Duration.minutes(5)), + test: synthetics.Test.custom({ + code: synthetics.Code.fromAsset(path.join(__dirname, 'canary')), + handler: 'index.handler', + }), + runtime: synthetics.Runtime.SYNTHETICS_NODEJS_PUPPETEER_7_0, + resourcesToReplicateTags: [synthetics.ResourceToReplicateTags.LAMBDA_FUNCTION], +}); +``` + +When you specify `ResourceToReplicateTags.LAMBDA_FUNCTION` in the `resourcesToReplicateTags` property, CloudWatch Synthetics will keep the tags of the canary and the Lambda function synchronized. Any future changes you make to the canary's tags will also be applied to the function. + diff --git a/packages/aws-cdk-lib/aws-synthetics/lib/canary.ts b/packages/aws-cdk-lib/aws-synthetics/lib/canary.ts index a3817844c6b91..01ba685f7ced6 100644 --- a/packages/aws-cdk-lib/aws-synthetics/lib/canary.ts +++ b/packages/aws-cdk-lib/aws-synthetics/lib/canary.ts @@ -77,6 +77,20 @@ export enum Cleanup { LAMBDA = 'lambda', } +/** + * Resources that tags applied to a canary should be replicated to. + */ +export enum ResourceToReplicateTags { + /** + * Replicate canary tags to the Lambda function. + * + * When specified, CloudWatch Synthetics will keep the tags of the canary + * and the Lambda function synchronized. Any future changes made to the + * canary's tags will also be applied to the function. + */ + LAMBDA_FUNCTION = 'lambda-function', +} + /** * Options for specifying the s3 location that stores the data of each canary run. The artifacts bucket location **cannot** * be updated once the canary is created. @@ -309,7 +323,7 @@ export interface CanaryProps { * * If set to true, CDK will execute a dry run to validate the changes before applying them to the canary. * If the dry run succeeds, the canary will be updated with the changes. - * If the dry run fails, the CloudFormation deployment will fail with the dry run’s failure reason. + * If the dry run fails, the CloudFormation deployment will fail with the dry run's failure reason. * * If set to false or omitted, the canary will be updated directly without first performing a dry run. * @@ -318,6 +332,19 @@ export interface CanaryProps { * @default undefined - AWS CloudWatch default is false */ readonly dryRunAndUpdate?: boolean; + + /** + * Specifies which resources should have their tags replicated to this canary. + * + * To have the tags that you apply to this canary also be applied to the Lambda + * function that the canary uses, specify this property with the value + * ResourceToReplicateTags.LAMBDA_FUNCTION. If you do this, CloudWatch Synthetics will keep the tags of the canary and the + * Lambda function synchronized. Any future changes you make to the canary's tags + * will also be applied to the function. + * + * @default - No resources will have their tags replicated to this canary + */ + readonly resourcesToReplicateTags?: ResourceToReplicateTags[]; } /** @@ -433,6 +460,7 @@ export class Canary extends cdk.Resource implements ec2.IConnectable { : 'OFF' : undefined, dryRunAndUpdate: props.dryRunAndUpdate, + resourcesToReplicateTags: props.resourcesToReplicateTags, }); this._resource = resource; diff --git a/packages/aws-cdk-lib/aws-synthetics/test/canary.test.ts b/packages/aws-cdk-lib/aws-synthetics/test/canary.test.ts index ab956ae36d327..283ddefc0d163 100644 --- a/packages/aws-cdk-lib/aws-synthetics/test/canary.test.ts +++ b/packages/aws-cdk-lib/aws-synthetics/test/canary.test.ts @@ -1191,3 +1191,72 @@ describe('artifact encryption test', () => { }).toThrow('Artifact encryption is only supported for canaries that use Synthetics runtime version \`syn-nodejs-puppeteer-3.3\` or later and the Playwright runtime, got syn-python-selenium-3.0.'); }); }); + +test('can configure resourcesToReplicateTags', () => { + // GIVEN + const stack = new Stack(); + + // WHEN + new synthetics.Canary(stack, 'Canary', { + canaryName: 'mycanary', + test: synthetics.Test.custom({ + handler: 'index.handler', + code: synthetics.Code.fromInline('/* Synthetics handler code */'), + }), + runtime: synthetics.Runtime.SYNTHETICS_NODEJS_PUPPETEER_8_0, + resourcesToReplicateTags: [synthetics.ResourceToReplicateTags.LAMBDA_FUNCTION], + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::Synthetics::Canary', { + Name: 'mycanary', + ResourcesToReplicateTags: ['lambda-function'], + }); +}); + +test('resourcesToReplicateTags is not included when not specified', () => { + // GIVEN + const stack = new Stack(); + + // WHEN + new synthetics.Canary(stack, 'Canary', { + canaryName: 'mycanary', + test: synthetics.Test.custom({ + handler: 'index.handler', + code: synthetics.Code.fromInline('/* Synthetics handler code */'), + }), + runtime: synthetics.Runtime.SYNTHETICS_NODEJS_PUPPETEER_8_0, + }); + + // THEN + const template = Template.fromStack(stack); + template.hasResourceProperties('AWS::Synthetics::Canary', { + Name: 'mycanary', + }); + + const canaryResource = template.findResources('AWS::Synthetics::Canary'); + const canaryProps = canaryResource[Object.keys(canaryResource)[0]].Properties; + expect(canaryProps.ResourcesToReplicateTags).toBeUndefined(); +}); + +test('resourcesToReplicateTags can be empty array', () => { + // GIVEN + const stack = new Stack(); + + // WHEN + new synthetics.Canary(stack, 'Canary', { + canaryName: 'mycanary', + test: synthetics.Test.custom({ + handler: 'index.handler', + code: synthetics.Code.fromInline('/* Synthetics handler code */'), + }), + runtime: synthetics.Runtime.SYNTHETICS_NODEJS_PUPPETEER_8_0, + resourcesToReplicateTags: [], + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::Synthetics::Canary', { + Name: 'mycanary', + ResourcesToReplicateTags: [], + }); +});