From dd6ad0768e40b1ad91caeb6fe56f608d4384b8d7 Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Mon, 13 Dec 2021 10:35:18 +0100 Subject: [PATCH 01/24] fix(region-info): ssm service principal format depends on region --- packages/@aws-cdk/aws-iam/lib/principals.ts | 46 +++++- packages/@aws-cdk/aws-iam/lib/util.ts | 8 + packages/@aws-cdk/aws-iam/package.json | 1 + .../@aws-cdk/aws-iam/test/principals.test.ts | 17 ++ .../region-info/build-tools/aws-entities.ts | 53 ------- .../region-info/build-tools/fact-tables.ts | 12 -- .../build-tools/generate-static-data.ts | 12 +- .../@aws-cdk/region-info/lib/aws-entities.ts | 147 ++++++++++++++++++ packages/@aws-cdk/region-info/lib/default.ts | 47 ++++-- packages/@aws-cdk/region-info/lib/fact.ts | 4 +- .../__snapshots__/region-info.test.js.snap | 108 +++++++++++++ .../@aws-cdk/region-info/test/default.test.ts | 10 ++ .../@aws-cdk/region-info/test/fact.test.ts | 2 +- .../region-info/test/region-info.test.ts | 2 +- 14 files changed, 376 insertions(+), 93 deletions(-) delete mode 100644 packages/@aws-cdk/region-info/build-tools/aws-entities.ts create mode 100644 packages/@aws-cdk/region-info/lib/aws-entities.ts diff --git a/packages/@aws-cdk/aws-iam/lib/principals.ts b/packages/@aws-cdk/aws-iam/lib/principals.ts index 001792cbcc475..a2d76c3b0e85c 100644 --- a/packages/@aws-cdk/aws-iam/lib/principals.ts +++ b/packages/@aws-cdk/aws-iam/lib/principals.ts @@ -1,5 +1,5 @@ import * as cdk from '@aws-cdk/core'; -import { Default, RegionInfo } from '@aws-cdk/region-info'; +import { Default, Fact, FactName, RegionInfo } from '@aws-cdk/region-info'; import { IOpenIdConnectProvider } from './oidc-provider'; import { Condition, Conditions, PolicyStatement } from './policy-statement'; import { ISamlProvider } from './saml-provider'; @@ -694,9 +694,14 @@ class ServicePrincipalToken implements cdk.IResolvable { } public resolve(ctx: cdk.IResolveContext) { - const region = this.opts.region || cdk.Stack.of(ctx.scope).region; - const fact = RegionInfo.get(region).servicePrincipal(this.service); - return fact || Default.servicePrincipal(this.service, region, cdk.Aws.URL_SUFFIX); + const stack = cdk.Stack.of(ctx.scope); + const region = this.opts.region ?? stack.region; + return regionalFact( + stack, + region, + FactName.servicePrincipal(this.service), + Default.servicePrincipal(this.service, region, cdk.Aws.URL_SUFFIX), + ); } public toString() { @@ -714,3 +719,36 @@ class ServicePrincipalToken implements cdk.IResolvable { return `<${this.service}>`; } } + +function regionalFact(stack: cdk.Stack, region: string, factName: string, defaultValue: string) { + if (!cdk.Token.isUnresolved(region)) { + return Fact.find(region, factName) ?? defaultValue; + } + + const lookupMap = RegionInfo.regionMap(factName); + const lookupValues = Object.values(lookupMap); + + // If there are no lookups, just return the default + if (lookupValues.length === 0) { return defaultValue; } + + // If all values are the same, we can just return the value directly + if (lookupValues.length > 1 && lookupValues.every((v) => v === lookupValues[0])) { + return lookupValues[0]; + } + + return deployTimeLookup(stack, factName, lookupMap); +} + +function deployTimeLookup(stack: cdk.Stack, factName: string, mapValues: Record) { + const factKey = factName.replace(/[^a-zA-Z0-9]/g, '_').replace(/^service_principal_/, ''); + + const id = 'ServicePrincipalMap'; + let mapping = stack.node.tryFindChild(id) as cdk.CfnMapping | undefined; + if (!mapping) { + mapping = new cdk.CfnMapping(stack, id); + } + for (const [region, value] of Object.entries(mapValues)) { + mapping.setValue(region, factKey, value); + } + return mapping.findInMap(cdk.Aws.REGION, factKey); +} diff --git a/packages/@aws-cdk/aws-iam/lib/util.ts b/packages/@aws-cdk/aws-iam/lib/util.ts index 11ef02a44ff5c..de3d3a1d059d5 100644 --- a/packages/@aws-cdk/aws-iam/lib/util.ts +++ b/packages/@aws-cdk/aws-iam/lib/util.ts @@ -137,4 +137,12 @@ export class UniqueStringSet implements IResolvable, IPostProcessor { function isEmptyObject(x: { [key: string]: any }): boolean { return Object.keys(x).length === 0; +} + +export function mkdict(xs: ReadonlyArray): Record { + const ret: Record = {}; + for (const [key, value] of xs) { + ret[key] = value; + } + return ret; } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-iam/package.json b/packages/@aws-cdk/aws-iam/package.json index f3f4ab6f37d3c..5131d1c23670e 100644 --- a/packages/@aws-cdk/aws-iam/package.json +++ b/packages/@aws-cdk/aws-iam/package.json @@ -80,6 +80,7 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/assertions": "0.0.0", "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-iam/test/principals.test.ts b/packages/@aws-cdk/aws-iam/test/principals.test.ts index 1bf7d47950875..01c5a9c8b9525 100644 --- a/packages/@aws-cdk/aws-iam/test/principals.test.ts +++ b/packages/@aws-cdk/aws-iam/test/principals.test.ts @@ -1,4 +1,5 @@ import '@aws-cdk/assert-internal/jest'; +import { Template } from '@aws-cdk/assertions'; import { App, CfnOutput, Stack } from '@aws-cdk/core'; import * as iam from '../lib'; @@ -243,4 +244,20 @@ test('PrincipalWithConditions inherits principalAccount from AccountPrincipal ', // THEN expect(accountPrincipal.principalAccount).toStrictEqual('123456789012'); expect(principalWithConditions.principalAccount).toStrictEqual('123456789012'); +}); + +test('ServicePrincipal in agnostic stack generates lookup table', () => { + // GIVEN + const stack = new Stack(); + + // WHEN + new iam.Role(stack, 'Role', { + assumedBy: new iam.ServicePrincipal('ssm.amazonaws.com'), + }); + + // THEN + const template = Template.fromStack(stack); + const mappings = template.findMappings('ServicePrincipalMap'); + expect(mappings.ServicePrincipalMap['af-south-1']?.ssm).toEqual('ssm.af-south-1.amazonaws.com'); + expect(mappings.ServicePrincipalMap['us-east-1']?.ssm).toEqual('ssm.amazonaws.com'); }); \ No newline at end of file diff --git a/packages/@aws-cdk/region-info/build-tools/aws-entities.ts b/packages/@aws-cdk/region-info/build-tools/aws-entities.ts deleted file mode 100644 index 28c59828f7477..0000000000000 --- a/packages/@aws-cdk/region-info/build-tools/aws-entities.ts +++ /dev/null @@ -1,53 +0,0 @@ -/** - * The names of all (known) AWS regions - * - * Not in the list ==> no built-in data for that region. - */ -export const AWS_REGIONS = [ - 'af-south-1', // Africa (Cape Town) - 'ap-east-1', // Asia Pacific (Hong Kong) - 'ap-northeast-1', // Asia Pacific (Tokyo) - 'ap-northeast-2', // Asia Pacific (Seoul) - 'ap-northeast-3', // Asia Pacific (Osaka) - 'ap-south-1', // Asia Pacific (Mumbai) - 'ap-southeast-1', // Asia Pacific (Singapore) - 'ap-southeast-2', // Asia Pacific (Sydney) - 'ca-central-1', // Canada (Central) - 'cn-north-1', // China (Beijing) - 'cn-northwest-1', // China (Ningxia) - 'eu-central-1', // Europe (Frankfurt) - 'eu-north-1', // Europe (Stockholm) - 'eu-south-1', // Europe (Milan) - 'eu-west-1', // Europe (Ireland) - 'eu-west-2', // Europe (London) - 'eu-west-3', // Europe (Paris) - 'me-south-1', // Middle East (Bahrain) - 'sa-east-1', // South America (São Paulo) - 'us-east-1', // US East (N. Virginia) - 'us-east-2', // US East (Ohio) - 'us-gov-east-1', // AWS GovCloud (US-East) - 'us-gov-west-1', // AWS GovCloud (US-West) - 'us-iso-east-1', // AWS ISO - 'us-isob-east-1', // AWS ISO-B - 'us-west-1', // US West (N. California) - 'us-west-2', // US West (Oregon) -].sort(); - -/** - * Possibly non-exaustive list of all service names, used to locate service principals. - * - * Not in the list ==> default service principal mappings. - */ -export const AWS_SERVICES = [ - 'application-autoscaling', - 'autoscaling', - 'codedeploy', - 'ec2', - 'events', - 'lambda', - 'logs', - 's3', - 'sns', - 'sqs', - 'states', -].sort(); diff --git a/packages/@aws-cdk/region-info/build-tools/fact-tables.ts b/packages/@aws-cdk/region-info/build-tools/fact-tables.ts index 6d95f24e5a7e8..fbe719523c178 100644 --- a/packages/@aws-cdk/region-info/build-tools/fact-tables.ts +++ b/packages/@aws-cdk/region-info/build-tools/fact-tables.ts @@ -1,15 +1,3 @@ -export const AWS_OLDER_REGIONS = new Set([ - 'us-east-1', - 'us-west-1', - 'us-west-2', - 'us-gov-west-1', - 'ap-southeast-1', - 'ap-southeast-2', - 'ap-northeast-1', - 'sa-east-1', - 'eu-west-1', -]); - export const AWS_CDK_METADATA = new Set([ 'us-east-2', 'us-east-1', diff --git a/packages/@aws-cdk/region-info/build-tools/generate-static-data.ts b/packages/@aws-cdk/region-info/build-tools/generate-static-data.ts index 006de89d3994d..59dba34515784 100644 --- a/packages/@aws-cdk/region-info/build-tools/generate-static-data.ts +++ b/packages/@aws-cdk/region-info/build-tools/generate-static-data.ts @@ -1,9 +1,14 @@ import * as path from 'path'; import * as fs from 'fs-extra'; +import { + AWS_REGIONS, + AWS_SERVICES, + before, + RULE_S3_WEBSITE_REGIONAL_SUBDOMAIN, +} from '../lib/aws-entities'; import { Default } from '../lib/default'; -import { AWS_REGIONS, AWS_SERVICES } from './aws-entities'; import { - APPMESH_ECR_ACCOUNTS, AWS_CDK_METADATA, AWS_OLDER_REGIONS, CLOUDWATCH_LAMBDA_INSIGHTS_ARNS, DLC_REPOSITORY_ACCOUNTS, + APPMESH_ECR_ACCOUNTS, AWS_CDK_METADATA, CLOUDWATCH_LAMBDA_INSIGHTS_ARNS, DLC_REPOSITORY_ACCOUNTS, ELBV2_ACCOUNTS, FIREHOSE_CIDR_BLOCKS, PARTITION_MAP, ROUTE_53_BUCKET_WEBSITE_ZONE_IDS, EBS_ENV_ENDPOINT_HOSTED_ZONE_IDS, } from './fact-tables'; @@ -51,7 +56,7 @@ async function main(): Promise { registerFact(region, 'CDK_METADATA_RESOURCE_AVAILABLE', AWS_CDK_METADATA.has(region) ? 'YES' : 'NO'); - registerFact(region, 'S3_STATIC_WEBSITE_ENDPOINT', AWS_OLDER_REGIONS.has(region) + registerFact(region, 'S3_STATIC_WEBSITE_ENDPOINT', before(region, RULE_S3_WEBSITE_REGIONAL_SUBDOMAIN) ? `s3-website-${region}.${domainSuffix}` : `s3-website.${region}.${domainSuffix}`); @@ -59,7 +64,6 @@ async function main(): Promise { registerFact(region, 'EBS_ENV_ENDPOINT_HOSTED_ZONE_ID', EBS_ENV_ENDPOINT_HOSTED_ZONE_IDS[region] || ''); - registerFact(region, 'ELBV2_ACCOUNT', ELBV2_ACCOUNTS[region]); registerFact(region, 'DLC_REPOSITORY_ACCOUNT', DLC_REPOSITORY_ACCOUNTS[region]); diff --git a/packages/@aws-cdk/region-info/lib/aws-entities.ts b/packages/@aws-cdk/region-info/lib/aws-entities.ts new file mode 100644 index 0000000000000..49fdff7c9b529 --- /dev/null +++ b/packages/@aws-cdk/region-info/lib/aws-entities.ts @@ -0,0 +1,147 @@ +// Rule prefix +const RULE_ = 'RULE_'; + +/** + * After this point, SSM only creates regional principals anymore + */ +export const RULE_SSM_PRINCIPALS_ARE_REGIONAL = `${RULE_}SSM_PRINCIPALS_ARE_REGIONAL`; + +/** + * After this point, S3 website domains look like `s3-website.REGION.s3.amazonaws.com` + * + * Before this point, S3 website domains look like `s3-website-REGION.s3.amazonaws.com`. + */ +export const RULE_S3_WEBSITE_REGIONAL_SUBDOMAIN = `${RULE_}SSM_PRINCIPALS_ARE_REGIONAL`; + +/** + * List of AWS region, ordered by launch date (oldest to newest) + * + * The significance of this is that standards and conventions change over time. + * Generally, as rules are changed they only apply to new regions, and old + * regions are left as-is. + * + * We mix the list of regions with a list of rules that were introduced over + * time (rules are strings starting with `RULE_`). + * + * Therefore, if we want to know if a rule applies to a certain region, we + * only need to check its position in the list and compare it to when a + * rule was introduced. + */ +export const AWS_REGIONS_AND_RULES = [ + 'us-east-1', // US East (N. Virginia) + 'eu-west-1', // Europe (Ireland) + 'us-west-1', // US West (N. California) + 'ap-southeast-1', // Asia Pacific (Singapore) + 'ap-northeast-1', // Asia Pacific (Tokyo) + 'us-gov-west-1', // AWS GovCloud (US-West) + 'us-west-2', // US West (Oregon) + 'sa-east-1', // South America (São Paulo) + 'ap-southeast-2', // Asia Pacific (Sydney) + RULE_S3_WEBSITE_REGIONAL_SUBDOMAIN, + 'cn-north-1', // China (Beijing) + 'us-iso-east-1', // AWS ISO + 'eu-central-1', // Europe (Frankfurt) + 'ap-northeast-2', // Asia Pacific (Seoul) + 'ap-south-1', // Asia Pacific (Mumbai) + 'us-east-2', // US East (Ohio) + 'ca-central-1', // Canada (Central) + 'eu-west-2', // Europe (London) + 'us-isob-east-1', // AWS ISO-B + 'cn-northwest-1', // China (Ningxia) + 'eu-west-3', // Europe (Paris) + 'ap-northeast-3', // Asia Pacific (Osaka) + 'us-gov-east-1', // AWS GovCloud (US-East) + 'eu-north-1', // Europe (Stockholm) + RULE_SSM_PRINCIPALS_ARE_REGIONAL, + 'ap-east-1', // Asia Pacific (Hong Kong) + 'me-south-1', // Middle East (Bahrain) + 'eu-south-1', // Europe (Milan) + 'af-south-1', // Africa (Cape Town) + 'us-iso-west-1', // US ISO West + 'eu-south-2', // Europe (Spain) + 'ap-southeast-3', // Asia Pacific (Jakarta) +]; + +/** + * The names of all (known) AWS regions + * + * Not in the list ==> no built-in data for that region. + */ +export const AWS_REGIONS = AWS_REGIONS_AND_RULES + .filter((x) => !x.startsWith(RULE_)) + .sort(); + +/** + * Possibly non-exaustive list of all service names, used to locate service principals. + * + * Not in the list ==> default service principal mappings. + */ +export const AWS_SERVICES = [ + 'application-autoscaling', + 'autoscaling', + 'codedeploy', + 'ec2', + 'events', + 'lambda', + 'logs', + 's3', + 'ssm', + 'sns', + 'sqs', + 'states', +].sort(); + +/** + * Whether or not a region predates a given rule (or region). + * + * Unknown region => we have to assume no. + */ +export function before(region: string, ruleOrRegion: string) { + const ruleIx = AWS_REGIONS_AND_RULES.indexOf(ruleOrRegion); + if (ruleIx === -1) { + throw new Error(`Unknown rule: ${ruleOrRegion}`); + } + const regionIx = AWS_REGIONS_AND_RULES.indexOf(region); + return regionIx === -1 ? false : regionIx < ruleIx; +} + +/** + * Return all regions before a given rule was introduced (or region) + */ +export function regionsBefore(ruleOrRegion: string): string[] { + const ruleIx = AWS_REGIONS_AND_RULES.indexOf(ruleOrRegion); + if (ruleIx === -1) { + throw new Error(`Unknown rule: ${ruleOrRegion}`); + } + return AWS_REGIONS_AND_RULES.filter((_, i) => i < ruleIx).sort(); +} + +export interface Region { partition: string, domainSuffix: string } + +const PARTITION_MAP: { [region: string]: Region } = { + 'default': { partition: 'aws', domainSuffix: 'amazonaws.com' }, + 'cn-': { partition: 'aws-cn', domainSuffix: 'amazonaws.com.cn' }, + 'us-gov-': { partition: 'aws-us-gov', domainSuffix: 'amazonaws.com' }, + 'us-iso-': { partition: 'aws-iso', domainSuffix: 'c2s.ic.gov' }, + 'us-isob-': { partition: 'aws-iso-b', domainSuffix: 'sc2s.sgov.gov' }, +}; + +export function partitionInformation(region: string): Region { + for (const [prefix, info] of Object.entries(PARTITION_MAP)) { + if (region.startsWith(prefix)) { + return info; + } + } + return PARTITION_MAP.default; +} + +/** + * Build a lookup map for all regions + */ +export function generateRegionMap(cb: (region: string) => string): Record { + const ret: Record = {}; + for (const region of AWS_REGIONS) { + ret[region] = cb(region); + } + return ret; +} \ No newline at end of file diff --git a/packages/@aws-cdk/region-info/lib/default.ts b/packages/@aws-cdk/region-info/lib/default.ts index c0ae0cc2b28d5..c88264b73645d 100644 --- a/packages/@aws-cdk/region-info/lib/default.ts +++ b/packages/@aws-cdk/region-info/lib/default.ts @@ -1,3 +1,5 @@ +import { before, RULE_SSM_PRINCIPALS_ARE_REGIONAL } from './aws-entities'; + /** * Provides default values for certain regional information points. */ @@ -16,24 +18,24 @@ export class Default { * all you have is `{ "Ref": "AWS::Region" }`). This way you get the same defaulting behavior that is normally used * for built-in data. * - * @param service the name of the service (s3, s3.amazonaws.com, ...) + * @param serviceFqn the name of the service (s3, s3.amazonaws.com, ...) * @param region the region in which the service principal is needed. - * @param urlSuffix the URL suffix for the partition in which the region is located. + * @param urlSuffix deprecated and ignored. */ - public static servicePrincipal(service: string, region: string, urlSuffix: string): string { - const matches = service.match(/^([^.]+)(?:(?:\.amazonaws\.com(?:\.cn)?)|(?:\.c2s\.ic\.gov)|(?:\.sc2s\.sgov\.gov))?$/); - if (!matches) { + public static servicePrincipal(serviceFqn: string, region: string, urlSuffix: string): string { + Array.isArray(urlSuffix); + + const service = extractSimpleName(serviceFqn); + if (!service) { // Return "service" if it does not look like any of the following: // - s3 // - s3.amazonaws.com // - s3.amazonaws.com.cn // - s3.c2s.ic.gov // - s3.sc2s.sgov.gov - return service; + return serviceFqn; } - service = matches[1]; // Simplify the service name down to something like "s3" - // Exceptions for Service Principals in us-iso-* const US_ISO_EXCEPTIONS = new Set([ 'cloudhsm', @@ -42,12 +44,6 @@ export class Default { 'workspaces', ]); - // Exceptions for Service Principals in us-isob-* - const US_ISOB_EXCEPTIONS = new Set([ - 'dms', - 'states', - ]); - // Account for idiosyncratic Service Principals in `us-iso-*` regions if (region.startsWith('us-iso-') && US_ISO_EXCEPTIONS.has(service)) { switch (service) { @@ -61,6 +57,12 @@ export class Default { } } + // Exceptions for Service Principals in us-isob-* + const US_ISOB_EXCEPTIONS = new Set([ + 'dms', + 'states', + ]); + // Account for idiosyncratic Service Principals in `us-isob-*` regions if (region.startsWith('us-isob-') && US_ISOB_EXCEPTIONS.has(service)) { switch (service) { @@ -74,19 +76,25 @@ export class Default { } } + // SSM turned from global to regional at some point + if (service === 'ssm') { + return before(region, RULE_SSM_PRINCIPALS_ARE_REGIONAL) + ? `${service}.amazonaws.com` + : `${service}.${region}.amazonaws.com`; + } + switch (service) { - // Services with a regional AND partitional principal + // Services with a regional AND China-variable principal case 'codedeploy': case 'logs': return `${service}.${region}.${urlSuffix}`; // Services with a regional principal case 'states': - case 'ssm': return `${service}.${region}.amazonaws.com`; - // Services with a partitional principal case 'ec2': + // Services with principally a universal principal but a different one in China return `${service}.${urlSuffix}`; // Services with a universal principal across all regions/partitions (the default case) @@ -98,3 +106,8 @@ export class Default { private constructor() { } } + +function extractSimpleName(serviceFqn: string) { + const matches = serviceFqn.match(/^([^.]+)(?:(?:\.amazonaws\.com(?:\.cn)?)|(?:\.c2s\.ic\.gov)|(?:\.sc2s\.sgov\.gov))?$/); + return matches ? matches[1] : undefined; +} \ No newline at end of file diff --git a/packages/@aws-cdk/region-info/lib/fact.ts b/packages/@aws-cdk/region-info/lib/fact.ts index 8d4e33802be43..1abe83ecf1d47 100644 --- a/packages/@aws-cdk/region-info/lib/fact.ts +++ b/packages/@aws-cdk/region-info/lib/fact.ts @@ -1,3 +1,5 @@ +import { AWS_REGIONS } from './aws-entities'; + /** * A database of regional information. */ @@ -7,7 +9,7 @@ export class Fact { * may not be an exhaustive list of all available AWS regions. */ public static get regions(): string[] { - return Object.keys(this.database); + return AWS_REGIONS; } /** diff --git a/packages/@aws-cdk/region-info/test/__snapshots__/region-info.test.js.snap b/packages/@aws-cdk/region-info/test/__snapshots__/region-info.test.js.snap index f1797f8083af5..540322967a480 100644 --- a/packages/@aws-cdk/region-info/test/__snapshots__/region-info.test.js.snap +++ b/packages/@aws-cdk/region-info/test/__snapshots__/region-info.test.js.snap @@ -24,6 +24,7 @@ Object { "s3": "s3.amazonaws.com", "sns": "sns.amazonaws.com", "sqs": "sqs.amazonaws.com", + "ssm": "ssm.af-south-1.amazonaws.com", "states": "states.af-south-1.amazonaws.com", }, "vpcEndPointServiceNamePrefix": "com.amazonaws.vpce", @@ -50,6 +51,7 @@ Object { "s3": "s3.amazonaws.com", "sns": "sns.amazonaws.com", "sqs": "sqs.amazonaws.com", + "ssm": "ssm.ap-east-1.amazonaws.com", "states": "states.ap-east-1.amazonaws.com", }, "vpcEndPointServiceNamePrefix": "com.amazonaws.vpce", @@ -76,6 +78,7 @@ Object { "s3": "s3.amazonaws.com", "sns": "sns.amazonaws.com", "sqs": "sqs.amazonaws.com", + "ssm": "ssm.amazonaws.com", "states": "states.ap-northeast-1.amazonaws.com", }, "vpcEndPointServiceNamePrefix": "com.amazonaws.vpce", @@ -102,6 +105,7 @@ Object { "s3": "s3.amazonaws.com", "sns": "sns.amazonaws.com", "sqs": "sqs.amazonaws.com", + "ssm": "ssm.ap-northeast-2.amazonaws.com", "states": "states.ap-northeast-2.amazonaws.com", }, "vpcEndPointServiceNamePrefix": "com.amazonaws.vpce", @@ -128,6 +132,7 @@ Object { "s3": "s3.amazonaws.com", "sns": "sns.amazonaws.com", "sqs": "sqs.amazonaws.com", + "ssm": "ssm.ap-northeast-3.amazonaws.com", "states": "states.ap-northeast-3.amazonaws.com", }, "vpcEndPointServiceNamePrefix": "com.amazonaws.vpce", @@ -154,6 +159,7 @@ Object { "s3": "s3.amazonaws.com", "sns": "sns.amazonaws.com", "sqs": "sqs.amazonaws.com", + "ssm": "ssm.ap-south-1.amazonaws.com", "states": "states.ap-south-1.amazonaws.com", }, "vpcEndPointServiceNamePrefix": "com.amazonaws.vpce", @@ -180,6 +186,7 @@ Object { "s3": "s3.amazonaws.com", "sns": "sns.amazonaws.com", "sqs": "sqs.amazonaws.com", + "ssm": "ssm.amazonaws.com", "states": "states.ap-southeast-1.amazonaws.com", }, "vpcEndPointServiceNamePrefix": "com.amazonaws.vpce", @@ -206,10 +213,38 @@ Object { "s3": "s3.amazonaws.com", "sns": "sns.amazonaws.com", "sqs": "sqs.amazonaws.com", + "ssm": "ssm.amazonaws.com", "states": "states.ap-southeast-2.amazonaws.com", }, "vpcEndPointServiceNamePrefix": "com.amazonaws.vpce", }, + "ap-southeast-3": Object { + "cdkMetadataResourceAvailable": false, + "domainSuffix": "amazonaws.com", + "lambdaInsightsVersions": Object { + "1.0.54.0": undefined, + "1.0.86.0": undefined, + "1.0.89.0": undefined, + "1.0.98.0": undefined, + }, + "partition": "aws", + "s3StaticWebsiteEndpoint": "s3-website.ap-southeast-3.amazonaws.com", + "servicePrincipals": Object { + "application-autoscaling": "application-autoscaling.amazonaws.com", + "autoscaling": "autoscaling.amazonaws.com", + "codedeploy": "codedeploy.ap-southeast-3.amazonaws.com", + "ec2": "ec2.amazonaws.com", + "events": "events.amazonaws.com", + "lambda": "lambda.amazonaws.com", + "logs": "logs.ap-southeast-3.amazonaws.com", + "s3": "s3.amazonaws.com", + "sns": "sns.amazonaws.com", + "sqs": "sqs.amazonaws.com", + "ssm": "ssm.ap-southeast-3.amazonaws.com", + "states": "states.ap-southeast-3.amazonaws.com", + }, + "vpcEndPointServiceNamePrefix": "com.amazonaws.vpce", + }, "ca-central-1": Object { "cdkMetadataResourceAvailable": true, "domainSuffix": "amazonaws.com", @@ -232,6 +267,7 @@ Object { "s3": "s3.amazonaws.com", "sns": "sns.amazonaws.com", "sqs": "sqs.amazonaws.com", + "ssm": "ssm.ca-central-1.amazonaws.com", "states": "states.ca-central-1.amazonaws.com", }, "vpcEndPointServiceNamePrefix": "com.amazonaws.vpce", @@ -258,6 +294,7 @@ Object { "s3": "s3.amazonaws.com", "sns": "sns.amazonaws.com", "sqs": "sqs.amazonaws.com", + "ssm": "ssm.cn-north-1.amazonaws.com", "states": "states.cn-north-1.amazonaws.com", }, "vpcEndPointServiceNamePrefix": "cn.com.amazonaws.vpce", @@ -284,6 +321,7 @@ Object { "s3": "s3.amazonaws.com", "sns": "sns.amazonaws.com", "sqs": "sqs.amazonaws.com", + "ssm": "ssm.cn-northwest-1.amazonaws.com", "states": "states.cn-northwest-1.amazonaws.com", }, "vpcEndPointServiceNamePrefix": "cn.com.amazonaws.vpce", @@ -310,6 +348,7 @@ Object { "s3": "s3.amazonaws.com", "sns": "sns.amazonaws.com", "sqs": "sqs.amazonaws.com", + "ssm": "ssm.eu-central-1.amazonaws.com", "states": "states.eu-central-1.amazonaws.com", }, "vpcEndPointServiceNamePrefix": "com.amazonaws.vpce", @@ -336,6 +375,7 @@ Object { "s3": "s3.amazonaws.com", "sns": "sns.amazonaws.com", "sqs": "sqs.amazonaws.com", + "ssm": "ssm.eu-north-1.amazonaws.com", "states": "states.eu-north-1.amazonaws.com", }, "vpcEndPointServiceNamePrefix": "com.amazonaws.vpce", @@ -362,10 +402,38 @@ Object { "s3": "s3.amazonaws.com", "sns": "sns.amazonaws.com", "sqs": "sqs.amazonaws.com", + "ssm": "ssm.eu-south-1.amazonaws.com", "states": "states.eu-south-1.amazonaws.com", }, "vpcEndPointServiceNamePrefix": "com.amazonaws.vpce", }, + "eu-south-2": Object { + "cdkMetadataResourceAvailable": false, + "domainSuffix": "amazonaws.com", + "lambdaInsightsVersions": Object { + "1.0.54.0": undefined, + "1.0.86.0": undefined, + "1.0.89.0": undefined, + "1.0.98.0": undefined, + }, + "partition": "aws", + "s3StaticWebsiteEndpoint": "s3-website.eu-south-2.amazonaws.com", + "servicePrincipals": Object { + "application-autoscaling": "application-autoscaling.amazonaws.com", + "autoscaling": "autoscaling.amazonaws.com", + "codedeploy": "codedeploy.eu-south-2.amazonaws.com", + "ec2": "ec2.amazonaws.com", + "events": "events.amazonaws.com", + "lambda": "lambda.amazonaws.com", + "logs": "logs.eu-south-2.amazonaws.com", + "s3": "s3.amazonaws.com", + "sns": "sns.amazonaws.com", + "sqs": "sqs.amazonaws.com", + "ssm": "ssm.eu-south-2.amazonaws.com", + "states": "states.eu-south-2.amazonaws.com", + }, + "vpcEndPointServiceNamePrefix": "com.amazonaws.vpce", + }, "eu-west-1": Object { "cdkMetadataResourceAvailable": true, "domainSuffix": "amazonaws.com", @@ -388,6 +456,7 @@ Object { "s3": "s3.amazonaws.com", "sns": "sns.amazonaws.com", "sqs": "sqs.amazonaws.com", + "ssm": "ssm.amazonaws.com", "states": "states.eu-west-1.amazonaws.com", }, "vpcEndPointServiceNamePrefix": "com.amazonaws.vpce", @@ -414,6 +483,7 @@ Object { "s3": "s3.amazonaws.com", "sns": "sns.amazonaws.com", "sqs": "sqs.amazonaws.com", + "ssm": "ssm.eu-west-2.amazonaws.com", "states": "states.eu-west-2.amazonaws.com", }, "vpcEndPointServiceNamePrefix": "com.amazonaws.vpce", @@ -440,6 +510,7 @@ Object { "s3": "s3.amazonaws.com", "sns": "sns.amazonaws.com", "sqs": "sqs.amazonaws.com", + "ssm": "ssm.eu-west-3.amazonaws.com", "states": "states.eu-west-3.amazonaws.com", }, "vpcEndPointServiceNamePrefix": "com.amazonaws.vpce", @@ -466,6 +537,7 @@ Object { "s3": "s3.amazonaws.com", "sns": "sns.amazonaws.com", "sqs": "sqs.amazonaws.com", + "ssm": "ssm.me-south-1.amazonaws.com", "states": "states.me-south-1.amazonaws.com", }, "vpcEndPointServiceNamePrefix": "com.amazonaws.vpce", @@ -492,6 +564,7 @@ Object { "s3": "s3.amazonaws.com", "sns": "sns.amazonaws.com", "sqs": "sqs.amazonaws.com", + "ssm": "ssm.amazonaws.com", "states": "states.sa-east-1.amazonaws.com", }, "vpcEndPointServiceNamePrefix": "com.amazonaws.vpce", @@ -518,6 +591,7 @@ Object { "s3": "s3.amazonaws.com", "sns": "sns.amazonaws.com", "sqs": "sqs.amazonaws.com", + "ssm": "ssm.amazonaws.com", "states": "states.us-east-1.amazonaws.com", }, "vpcEndPointServiceNamePrefix": "com.amazonaws.vpce", @@ -544,6 +618,7 @@ Object { "s3": "s3.amazonaws.com", "sns": "sns.amazonaws.com", "sqs": "sqs.amazonaws.com", + "ssm": "ssm.us-east-2.amazonaws.com", "states": "states.us-east-2.amazonaws.com", }, "vpcEndPointServiceNamePrefix": "com.amazonaws.vpce", @@ -570,6 +645,7 @@ Object { "s3": "s3.amazonaws.com", "sns": "sns.amazonaws.com", "sqs": "sqs.amazonaws.com", + "ssm": "ssm.us-gov-east-1.amazonaws.com", "states": "states.us-gov-east-1.amazonaws.com", }, "vpcEndPointServiceNamePrefix": "com.amazonaws.vpce", @@ -596,6 +672,7 @@ Object { "s3": "s3.amazonaws.com", "sns": "sns.amazonaws.com", "sqs": "sqs.amazonaws.com", + "ssm": "ssm.amazonaws.com", "states": "states.us-gov-west-1.amazonaws.com", }, "vpcEndPointServiceNamePrefix": "com.amazonaws.vpce", @@ -622,6 +699,34 @@ Object { "s3": "s3.amazonaws.com", "sns": "sns.amazonaws.com", "sqs": "sqs.amazonaws.com", + "ssm": "ssm.us-iso-east-1.amazonaws.com", + "states": "states.amazonaws.com", + }, + "vpcEndPointServiceNamePrefix": "gov.ic.c2s.vpce", + }, + "us-iso-west-1": Object { + "cdkMetadataResourceAvailable": false, + "domainSuffix": "c2s.ic.gov", + "lambdaInsightsVersions": Object { + "1.0.54.0": undefined, + "1.0.86.0": undefined, + "1.0.89.0": undefined, + "1.0.98.0": undefined, + }, + "partition": "aws-iso", + "s3StaticWebsiteEndpoint": "s3-website.us-iso-west-1.c2s.ic.gov", + "servicePrincipals": Object { + "application-autoscaling": "application-autoscaling.amazonaws.com", + "autoscaling": "autoscaling.amazonaws.com", + "codedeploy": "codedeploy.us-iso-west-1.c2s.ic.gov", + "ec2": "ec2.c2s.ic.gov", + "events": "events.amazonaws.com", + "lambda": "lambda.amazonaws.com", + "logs": "logs.us-iso-west-1.c2s.ic.gov", + "s3": "s3.amazonaws.com", + "sns": "sns.amazonaws.com", + "sqs": "sqs.amazonaws.com", + "ssm": "ssm.us-iso-west-1.amazonaws.com", "states": "states.amazonaws.com", }, "vpcEndPointServiceNamePrefix": "gov.ic.c2s.vpce", @@ -648,6 +753,7 @@ Object { "s3": "s3.amazonaws.com", "sns": "sns.amazonaws.com", "sqs": "sqs.amazonaws.com", + "ssm": "ssm.us-isob-east-1.amazonaws.com", "states": "states.amazonaws.com", }, "vpcEndPointServiceNamePrefix": "gov.sgov.sc2s.vpce", @@ -674,6 +780,7 @@ Object { "s3": "s3.amazonaws.com", "sns": "sns.amazonaws.com", "sqs": "sqs.amazonaws.com", + "ssm": "ssm.amazonaws.com", "states": "states.us-west-1.amazonaws.com", }, "vpcEndPointServiceNamePrefix": "com.amazonaws.vpce", @@ -700,6 +807,7 @@ Object { "s3": "s3.amazonaws.com", "sns": "sns.amazonaws.com", "sqs": "sqs.amazonaws.com", + "ssm": "ssm.amazonaws.com", "states": "states.us-west-2.amazonaws.com", }, "vpcEndPointServiceNamePrefix": "com.amazonaws.vpce", diff --git a/packages/@aws-cdk/region-info/test/default.test.ts b/packages/@aws-cdk/region-info/test/default.test.ts index 1e7c1b166c9b6..7ee01e802a5bd 100644 --- a/packages/@aws-cdk/region-info/test/default.test.ts +++ b/packages/@aws-cdk/region-info/test/default.test.ts @@ -47,4 +47,14 @@ describe('servicePrincipal', () => { expect(Default.servicePrincipal(`${service}.amazonaws.com`, 'us-iso-east-1', 'c2s.ic.gov')).toBe(`${service}.c2s.ic.gov`); }); } + }); + + +describe('spot-check some service principals', () => { + test('ssm', () => { + expect(Default.servicePrincipal('ssm.amazonaws.com', 'us-east-1', 'x')).toBe('ssm.amazonaws.com'); + expect(Default.servicePrincipal('ssm.amazonaws.com', 'ap-east-1', 'x')).toBe('ssm.ap-east-1.amazonaws.com'); + expect(Default.servicePrincipal('ssm.amazonaws.com', 'eu-south-1', 'x')).toBe('ssm.eu-south-1.amazonaws.com'); + }); +}); \ No newline at end of file diff --git a/packages/@aws-cdk/region-info/test/fact.test.ts b/packages/@aws-cdk/region-info/test/fact.test.ts index 5522d4bd16d1d..b3e3bab7fdab7 100644 --- a/packages/@aws-cdk/region-info/test/fact.test.ts +++ b/packages/@aws-cdk/region-info/test/fact.test.ts @@ -1,5 +1,5 @@ -import { AWS_REGIONS } from '../build-tools/aws-entities'; import { Fact, FactName } from '../lib'; +import { AWS_REGIONS } from '../lib/aws-entities'; describe('find', () => { test('returns undefined for an unknown fact', () => { diff --git a/packages/@aws-cdk/region-info/test/region-info.test.ts b/packages/@aws-cdk/region-info/test/region-info.test.ts index 8c06907052b23..aab6e721cd35e 100644 --- a/packages/@aws-cdk/region-info/test/region-info.test.ts +++ b/packages/@aws-cdk/region-info/test/region-info.test.ts @@ -1,6 +1,6 @@ -import { AWS_REGIONS, AWS_SERVICES } from '../build-tools/aws-entities'; import { CLOUDWATCH_LAMBDA_INSIGHTS_ARNS } from '../build-tools/fact-tables'; import { RegionInfo } from '../lib'; +import { AWS_REGIONS, AWS_SERVICES } from '../lib/aws-entities'; test('built-in data is correct', () => { const snapshot: any = {}; From 2d67d2eed6a5d898a6561dc6167517c3c2cef3b8 Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Mon, 13 Dec 2021 11:33:21 +0100 Subject: [PATCH 02/24] Add flag to control regions that are rendered --- packages/@aws-cdk/aws-iam/lib/principals.ts | 39 +-------- .../aws-lambda/lib/lambda-insights.ts | 49 +---------- packages/@aws-cdk/core/lib/stack.ts | 85 ++++++++++++++++++- packages/@aws-cdk/cx-api/lib/features.ts | 13 ++- .../@aws-cdk/region-info/lib/region-info.ts | 21 +++++ .../region-info/test/region-info.test.ts | 13 ++- .../cdk-integ-tools/lib/integ-helpers.ts | 5 +- 7 files changed, 137 insertions(+), 88 deletions(-) diff --git a/packages/@aws-cdk/aws-iam/lib/principals.ts b/packages/@aws-cdk/aws-iam/lib/principals.ts index a2d76c3b0e85c..0d23c11774461 100644 --- a/packages/@aws-cdk/aws-iam/lib/principals.ts +++ b/packages/@aws-cdk/aws-iam/lib/principals.ts @@ -1,5 +1,5 @@ import * as cdk from '@aws-cdk/core'; -import { Default, Fact, FactName, RegionInfo } from '@aws-cdk/region-info'; +import { Default, FactName } from '@aws-cdk/region-info'; import { IOpenIdConnectProvider } from './oidc-provider'; import { Condition, Conditions, PolicyStatement } from './policy-statement'; import { ISamlProvider } from './saml-provider'; @@ -696,9 +696,7 @@ class ServicePrincipalToken implements cdk.IResolvable { public resolve(ctx: cdk.IResolveContext) { const stack = cdk.Stack.of(ctx.scope); const region = this.opts.region ?? stack.region; - return regionalFact( - stack, - region, + return stack.regionalFact( FactName.servicePrincipal(this.service), Default.servicePrincipal(this.service, region, cdk.Aws.URL_SUFFIX), ); @@ -719,36 +717,3 @@ class ServicePrincipalToken implements cdk.IResolvable { return `<${this.service}>`; } } - -function regionalFact(stack: cdk.Stack, region: string, factName: string, defaultValue: string) { - if (!cdk.Token.isUnresolved(region)) { - return Fact.find(region, factName) ?? defaultValue; - } - - const lookupMap = RegionInfo.regionMap(factName); - const lookupValues = Object.values(lookupMap); - - // If there are no lookups, just return the default - if (lookupValues.length === 0) { return defaultValue; } - - // If all values are the same, we can just return the value directly - if (lookupValues.length > 1 && lookupValues.every((v) => v === lookupValues[0])) { - return lookupValues[0]; - } - - return deployTimeLookup(stack, factName, lookupMap); -} - -function deployTimeLookup(stack: cdk.Stack, factName: string, mapValues: Record) { - const factKey = factName.replace(/[^a-zA-Z0-9]/g, '_').replace(/^service_principal_/, ''); - - const id = 'ServicePrincipalMap'; - let mapping = stack.node.tryFindChild(id) as cdk.CfnMapping | undefined; - if (!mapping) { - mapping = new cdk.CfnMapping(stack, id); - } - for (const [region, value] of Object.entries(mapValues)) { - mapping.setValue(region, factKey, value); - } - return mapping.findInMap(cdk.Aws.REGION, factKey); -} diff --git a/packages/@aws-cdk/aws-lambda/lib/lambda-insights.ts b/packages/@aws-cdk/aws-lambda/lib/lambda-insights.ts index 2d2b88511786e..dab2ad072523d 100644 --- a/packages/@aws-cdk/aws-lambda/lib/lambda-insights.ts +++ b/packages/@aws-cdk/aws-lambda/lib/lambda-insights.ts @@ -1,9 +1,6 @@ -import { Aws, CfnMapping, Fn, IResolveContext, Lazy, Stack, Token } from '@aws-cdk/core'; +import { IResolveContext, Lazy, Stack, Token } from '@aws-cdk/core'; import { FactName, RegionInfo } from '@aws-cdk/region-info'; -// This is the name of the mapping that will be added to the CloudFormation template, if a stack is region agnostic -const DEFAULT_MAPPING_PREFIX = 'LambdaInsightsVersions'; - // To add new versions, update fact-tables.ts `CLOUDWATCH_LAMBDA_INSIGHTS_ARNS` and create a new `public static readonly VERSION_A_B_C_D` /** @@ -88,47 +85,5 @@ function getVersionArn(context: IResolveContext, insightsVersion: string): strin } // Otherwise, need to add a mapping to be looked up at deployment time - - /** - * See this for the context as to why the mappings are the way they are - * https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/mappings-section-structure.html - * - * Mappings have to have a structure like this, and no functions can be used inside them: - * - * - - * -- { : "value1"}, - * -- { : "value2"} - * - * So we cannot have an otherwise ideal mapping like this, because '1.0.98.0' is non-alphanumeric: - * LambdaInsightsVersions - * - us-east-1 - * -- {'1.0.98.0': 'arn1'}, - * -- {'1.0.89.0': 'arn2'} - * - * To get around this limitation, this is the mapping structure: - * LambdaInsightsVersions10980 // for version 1.0.98.0 - * - us-east-1 - * -- {'arn': 'arn1'}, - * - us-east-2 - * -- {'arn': 'arn2'} - * LambdaInsightsVersions10890 // a separate mapping version 1.0.89.0 - * - us-east-1 - * -- {'arn': 'arn3'}, - * - us-east-2 - * -- {'arn': 'arn4'} - */ - - const mapName = DEFAULT_MAPPING_PREFIX + insightsVersion.split('.').join(''); - const mapping: { [k1: string]: { [k2: string]: any } } = {}; - const region2arns = RegionInfo.regionMap(FactName.cloudwatchLambdaInsightsVersion(insightsVersion)); - for (const [reg, arn] of Object.entries(region2arns)) { - mapping[reg] = { arn }; - } - - // Only create a given mapping once. If another version of insights is used elsewhere, that mapping will also exist - if (!scopeStack.node.tryFindChild(mapName)) { - new CfnMapping(scopeStack, mapName, { mapping }); - } - // The ARN will be looked up at deployment time from the mapping we created - return Fn.findInMap(mapName, Aws.REGION, 'arn'); + return scopeStack.regionalFact(FactName.cloudwatchLambdaInsightsVersion(insightsVersion)); } \ No newline at end of file diff --git a/packages/@aws-cdk/core/lib/stack.ts b/packages/@aws-cdk/core/lib/stack.ts index 6645805519b81..ee8d97d3a4ae1 100644 --- a/packages/@aws-cdk/core/lib/stack.ts +++ b/packages/@aws-cdk/core/lib/stack.ts @@ -803,6 +803,59 @@ export class Stack extends CoreConstruct implements ITaggable { } } + /** + * Look up a fact value for the given fact for the region of this stack + * + * Will return a definite value only if the region of the current stack is resolved. + * If not, a lookup map will be added to the stack and the lookup will be done at + * CDK deployment time. + * + * What regions will be included in the lookup map is controlled by the + * `@aws-cdk/core:target-partitions` context value: it must be set to a list + * of partitions, and only regions from the given partitions will be included. + * If no such context key is set, all regions will be included. + * + * This function is intended to be used by construct library authors. Application + * builders can rely on the abstractions offered by construct libraries and do + * not have to worry about regional facts. + * + * If `defaultValue` is not given, it is an error if the fact is unknown for + * the given region. + */ + public regionalFact(factName: string, defaultValue?: string): string { + if (!Token.isUnresolved(this.region)) { + const ret = Fact.find(this.region, factName) ?? defaultValue; + if (ret === undefined) { + throw new Error(`region-info: don't know ${factName} for region ${this.region}. Use 'Fact.register' to provide this value.`); + } + return ret; + } + + const regions = Node.of(this).tryGetContext(cxapi.TARGET_PARTITIONS); + if (regions !== undefined && !Array.isArray(regions)) { + throw new Error(`Context value '${cxapi.TARGET_PARTITIONS}' should be a list of strings, got: ${JSON.stringify(cxapi.TARGET_PARTITIONS)}`); + } + + const lookupMap = regions ? RegionInfo.limitedRegionMap(factName, regions) : RegionInfo.regionMap(factName); + const lookupValues = Object.values(lookupMap); + + // If there are no lookups, just return the default + if (lookupValues.length === 0) { + if (!defaultValue) { + throw new Error(`region-info: don't have any information for ${factName}. Use 'Fact.register' to provide values, or add partitions to the '${cxapi.TARGET_PARTITIONS}' context value.`); + } + return defaultValue; + } + + // If all values are the same, we can just return the value directly + if (lookupValues.length > 1 && lookupValues.every((v) => v === lookupValues[0])) { + return lookupValues[0]; + } + + return deployTimeLookup(this, factName, lookupMap); + } + + /** * Create a CloudFormation Export for a value * @@ -1301,6 +1354,34 @@ export interface ExportValueOptions { readonly name?: string; } +/** + * Make sure a CfnMapping exists in the given stack with the lookup values for the given fact + * + * Add to an existing CfnMapping if possible. + */ +function deployTimeLookup(stack: Stack, factName: string, mapValues: Record) { + // Derive map name and lookup key from the factName, splitting on ':' if it exists + const [factClass, factParam] = factName.includes(':') + ? factName.split(':') + : [factName, 'value'] as const; + + const mapId = `${ucfirst(factClass)}Map`; + const factKey = factParam.replace(/[^a-zA-Z0-9]/g, '_'); + + let mapping = stack.node.tryFindChild(mapId) as CfnMapping | undefined; + if (!mapping) { + mapping = new CfnMapping(stack, mapId); + } + for (const [region, value] of Object.entries(mapValues)) { + mapping.setValue(region, factKey, value); + } + return mapping.findInMap(Aws.REGION, factKey); +} + +function ucfirst(x: string) { + return `${x.substr(0, 1).toUpperCase()}${x.substr(1)}`; +} + // These imports have to be at the end to prevent circular imports import { CfnOutput } from './cfn-output'; import { addDependency } from './deps'; @@ -1312,4 +1393,6 @@ import { DefaultStackSynthesizer, IStackSynthesizer, LegacyStackSynthesizer } fr import { Stage } from './stage'; import { ITaggable, TagManager } from './tag-manager'; import { Token, Tokenization } from './token'; -import { referenceNestedStackValueInParent } from './private/refs'; +import { referenceNestedStackValueInParent } from './private/refs';import { Fact, RegionInfo } from '@aws-cdk/region-info'; +import { CfnMapping } from './cfn-mapping'; + diff --git a/packages/@aws-cdk/cx-api/lib/features.ts b/packages/@aws-cdk/cx-api/lib/features.ts index 37c9aace0ce86..e63f4a9ec7b7b 100644 --- a/packages/@aws-cdk/cx-api/lib/features.ts +++ b/packages/@aws-cdk/cx-api/lib/features.ts @@ -161,7 +161,17 @@ export const LAMBDA_RECOGNIZE_VERSION_PROPS = '@aws-cdk/aws-lambda:recognizeVers export const CLOUDFRONT_DEFAULT_SECURITY_POLICY_TLS_V1_2_2021 = '@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021'; /** - * This map includes context keys and values for feature flags that enable + * What regions to include in lookup tables of environment agnostic stacks + * + * Has no effect on stacks that have a defined region, but will limit the amount + * of unnecessary regions included in stacks without a known region. + * + * The type of this value should be a list of strings. + */ +export const TARGET_PARTITIONS = '@aws-cdk/core:target-partitions'; + +/** + * This map includes context keys and values for feature flags that enable * capabilities "from the future", which we could not introduce as the default * behavior due to backwards compatibility for existing projects. * @@ -187,6 +197,7 @@ export const FUTURE_FLAGS: { [key: string]: any } = { [EFS_DEFAULT_ENCRYPTION_AT_REST]: true, [LAMBDA_RECOGNIZE_VERSION_PROPS]: true, [CLOUDFRONT_DEFAULT_SECURITY_POLICY_TLS_V1_2_2021]: true, + [TARGET_PARTITIONS]: ['aws', 'aws-cn'], // We will advertise this flag when the feature is complete // [NEW_STYLE_STACK_SYNTHESIS_CONTEXT]: 'true', diff --git a/packages/@aws-cdk/region-info/lib/region-info.ts b/packages/@aws-cdk/region-info/lib/region-info.ts index 3482acf66b9a1..e5f9e1ae0e62f 100644 --- a/packages/@aws-cdk/region-info/lib/region-info.ts +++ b/packages/@aws-cdk/region-info/lib/region-info.ts @@ -1,3 +1,4 @@ +import { partitionInformation } from './aws-entities'; import { Fact, FactName } from './fact'; /** @@ -31,6 +32,26 @@ export class RegionInfo { return ret; } + /** + * Retrieves a collection of all fact values for all regions, limited to some partitions + * + * @param factName the name of the fact to retrieve values for. + * For a list of common fact names, see the FactName class + * @param partitions list of partitions to retrieve facts for. Defaults + * to `['aws', 'aws-cn']`. + * @returns a mapping with AWS region codes as the keys, + * and the fact in the given region as the value for that key + */ + public static limitedRegionMap(factName: string, partitions: string[]): { [region: string]: string } { + const ret: Record = {}; + for (const [region, value] of Object.entries(RegionInfo.regionMap(factName))) { + if (partitions.includes(partitionInformation(region).partition)) { + ret[region] = value; + } + } + return ret; + } + /** * Obtain region info for a given region name. * diff --git a/packages/@aws-cdk/region-info/test/region-info.test.ts b/packages/@aws-cdk/region-info/test/region-info.test.ts index aab6e721cd35e..5160acfa618f6 100644 --- a/packages/@aws-cdk/region-info/test/region-info.test.ts +++ b/packages/@aws-cdk/region-info/test/region-info.test.ts @@ -1,5 +1,5 @@ import { CLOUDWATCH_LAMBDA_INSIGHTS_ARNS } from '../build-tools/fact-tables'; -import { RegionInfo } from '../lib'; +import { FactName, RegionInfo } from '../lib'; import { AWS_REGIONS, AWS_SERVICES } from '../lib/aws-entities'; test('built-in data is correct', () => { @@ -36,3 +36,14 @@ test('built-in data features known regions', () => { expect(regions.map(region => region.name)).toContain(expected); } }); + +test('limitedRegionMap only returns information for certain regions', () => { + + const map = RegionInfo.limitedRegionMap(FactName.ELBV2_ACCOUNT, ['aws']); + expect(map['us-east-1']).toBeDefined(); + expect(map['cn-north-1']).not.toBeDefined(); + + const map2 = RegionInfo.limitedRegionMap(FactName.ELBV2_ACCOUNT, ['aws-cn']); + expect(map2['us-east-1']).not.toBeDefined(); + expect(map2['cn-north-1']).toBeDefined(); +}); diff --git a/tools/@aws-cdk/cdk-integ-tools/lib/integ-helpers.ts b/tools/@aws-cdk/cdk-integ-tools/lib/integ-helpers.ts index 6b725d980a6f6..52d330b307110 100644 --- a/tools/@aws-cdk/cdk-integ-tools/lib/integ-helpers.ts +++ b/tools/@aws-cdk/cdk-integ-tools/lib/integ-helpers.ts @@ -1,7 +1,7 @@ // Helper functions for integration tests import { spawnSync } from 'child_process'; import * as path from 'path'; -import { AVAILABILITY_ZONE_FALLBACK_CONTEXT_KEY, FUTURE_FLAGS } from '@aws-cdk/cx-api'; +import { AVAILABILITY_ZONE_FALLBACK_CONTEXT_KEY, FUTURE_FLAGS, TARGET_PARTITIONS } from '@aws-cdk/cx-api'; import * as fs from 'fs-extra'; const CDK_OUTDIR = 'cdk-integ.out'; @@ -353,6 +353,9 @@ export const DEFAULT_SYNTH_OPTIONS = { }, // Enable feature flags for all integ tests ...FUTURE_FLAGS, + + // Restrict target partitions to only 'aws', so all service principals stay the same + [TARGET_PARTITIONS]: ['aws'], }, env: { CDK_INTEG_ACCOUNT: '12345678', From d7553270d228549c03670399ce3dda1ce08c1338 Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Mon, 13 Dec 2021 12:03:50 +0100 Subject: [PATCH 03/24] Fix some tests --- packages/@aws-cdk/aws-iam/lib/principals.ts | 18 +++++++++++++++--- packages/@aws-cdk/aws-iam/lib/util.ts | 8 -------- .../@aws-cdk/aws-iam/test/principals.test.ts | 6 +++--- packages/@aws-cdk/region-info/lib/default.ts | 6 ++---- 4 files changed, 20 insertions(+), 18 deletions(-) diff --git a/packages/@aws-cdk/aws-iam/lib/principals.ts b/packages/@aws-cdk/aws-iam/lib/principals.ts index 0d23c11774461..5a3abd6c0a76d 100644 --- a/packages/@aws-cdk/aws-iam/lib/principals.ts +++ b/packages/@aws-cdk/aws-iam/lib/principals.ts @@ -1,5 +1,5 @@ import * as cdk from '@aws-cdk/core'; -import { Default, FactName } from '@aws-cdk/region-info'; +import { Default, FactName, RegionInfo } from '@aws-cdk/region-info'; import { IOpenIdConnectProvider } from './oidc-provider'; import { Condition, Conditions, PolicyStatement } from './policy-statement'; import { ISamlProvider } from './saml-provider'; @@ -331,6 +331,7 @@ export interface ServicePrincipalOpts { * The region in which the service is operating. * * @default the current Stack's region. + * @deprecated You should not need to set this. The stack's region is always correct. */ readonly region?: string; @@ -694,11 +695,22 @@ class ServicePrincipalToken implements cdk.IResolvable { } public resolve(ctx: cdk.IResolveContext) { + if (this.opts.region) { + // Special case, handle it separately to not break legacy behavior. + return ( + RegionInfo.get(this.opts.region).servicePrincipal(this.service) ?? + Default.servicePrincipal( + this.service, + this.opts.region, + cdk.Aws.URL_SUFFIX, + ) + ); + } + const stack = cdk.Stack.of(ctx.scope); - const region = this.opts.region ?? stack.region; return stack.regionalFact( FactName.servicePrincipal(this.service), - Default.servicePrincipal(this.service, region, cdk.Aws.URL_SUFFIX), + Default.servicePrincipal(this.service, stack.region, cdk.Aws.URL_SUFFIX), ); } diff --git a/packages/@aws-cdk/aws-iam/lib/util.ts b/packages/@aws-cdk/aws-iam/lib/util.ts index de3d3a1d059d5..831f625a1fdcf 100644 --- a/packages/@aws-cdk/aws-iam/lib/util.ts +++ b/packages/@aws-cdk/aws-iam/lib/util.ts @@ -138,11 +138,3 @@ export class UniqueStringSet implements IResolvable, IPostProcessor { function isEmptyObject(x: { [key: string]: any }): boolean { return Object.keys(x).length === 0; } - -export function mkdict(xs: ReadonlyArray): Record { - const ret: Record = {}; - for (const [key, value] of xs) { - ret[key] = value; - } - return ret; -} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-iam/test/principals.test.ts b/packages/@aws-cdk/aws-iam/test/principals.test.ts index 01c5a9c8b9525..18dc72f4d760b 100644 --- a/packages/@aws-cdk/aws-iam/test/principals.test.ts +++ b/packages/@aws-cdk/aws-iam/test/principals.test.ts @@ -257,7 +257,7 @@ test('ServicePrincipal in agnostic stack generates lookup table', () => { // THEN const template = Template.fromStack(stack); - const mappings = template.findMappings('ServicePrincipalMap'); - expect(mappings.ServicePrincipalMap['af-south-1']?.ssm).toEqual('ssm.af-south-1.amazonaws.com'); - expect(mappings.ServicePrincipalMap['us-east-1']?.ssm).toEqual('ssm.amazonaws.com'); + const mappings = template.findMappings('ServiceprincipalMap'); + expect(mappings.ServiceprincipalMap['af-south-1']?.ssm).toEqual('ssm.af-south-1.amazonaws.com'); + expect(mappings.ServiceprincipalMap['us-east-1']?.ssm).toEqual('ssm.amazonaws.com'); }); \ No newline at end of file diff --git a/packages/@aws-cdk/region-info/lib/default.ts b/packages/@aws-cdk/region-info/lib/default.ts index c88264b73645d..5310569bf6069 100644 --- a/packages/@aws-cdk/region-info/lib/default.ts +++ b/packages/@aws-cdk/region-info/lib/default.ts @@ -23,8 +23,6 @@ export class Default { * @param urlSuffix deprecated and ignored. */ public static servicePrincipal(serviceFqn: string, region: string, urlSuffix: string): string { - Array.isArray(urlSuffix); - const service = extractSimpleName(serviceFqn); if (!service) { // Return "service" if it does not look like any of the following: @@ -84,7 +82,7 @@ export class Default { } switch (service) { - // Services with a regional AND China-variable principal + // Services with a regional AND partitional principal case 'codedeploy': case 'logs': return `${service}.${region}.${urlSuffix}`; @@ -93,8 +91,8 @@ export class Default { case 'states': return `${service}.${region}.amazonaws.com`; + // Services with a partitional pricnipal case 'ec2': - // Services with principally a universal principal but a different one in China return `${service}.${urlSuffix}`; // Services with a universal principal across all regions/partitions (the default case) From f572278a17a72fd03081ffaf29ba179d7e524cd1 Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Mon, 13 Dec 2021 13:43:18 +0100 Subject: [PATCH 04/24] Update packages/@aws-cdk/region-info/lib/default.ts Co-authored-by: Nick Lynch --- packages/@aws-cdk/region-info/lib/default.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@aws-cdk/region-info/lib/default.ts b/packages/@aws-cdk/region-info/lib/default.ts index 5310569bf6069..b11aa881f955c 100644 --- a/packages/@aws-cdk/region-info/lib/default.ts +++ b/packages/@aws-cdk/region-info/lib/default.ts @@ -91,7 +91,7 @@ export class Default { case 'states': return `${service}.${region}.amazonaws.com`; - // Services with a partitional pricnipal + // Services with a partitional principal case 'ec2': return `${service}.${urlSuffix}`; From 75493903d972281536ba29dd094610f93b3e53f9 Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Mon, 13 Dec 2021 13:43:24 +0100 Subject: [PATCH 05/24] Update packages/@aws-cdk/region-info/lib/aws-entities.ts Co-authored-by: Nick Lynch --- packages/@aws-cdk/region-info/lib/aws-entities.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@aws-cdk/region-info/lib/aws-entities.ts b/packages/@aws-cdk/region-info/lib/aws-entities.ts index 49fdff7c9b529..30d8bc8c2c1d4 100644 --- a/packages/@aws-cdk/region-info/lib/aws-entities.ts +++ b/packages/@aws-cdk/region-info/lib/aws-entities.ts @@ -2,7 +2,7 @@ const RULE_ = 'RULE_'; /** - * After this point, SSM only creates regional principals anymore + * After this point, SSM only creates regional principals */ export const RULE_SSM_PRINCIPALS_ARE_REGIONAL = `${RULE_}SSM_PRINCIPALS_ARE_REGIONAL`; From 45fba99aa2b35b951058bba64e93a929f7dfa8dd Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Mon, 13 Dec 2021 13:43:29 +0100 Subject: [PATCH 06/24] Update packages/@aws-cdk/cx-api/lib/features.ts Co-authored-by: Nick Lynch --- packages/@aws-cdk/cx-api/lib/features.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@aws-cdk/cx-api/lib/features.ts b/packages/@aws-cdk/cx-api/lib/features.ts index e63f4a9ec7b7b..136de413f2c51 100644 --- a/packages/@aws-cdk/cx-api/lib/features.ts +++ b/packages/@aws-cdk/cx-api/lib/features.ts @@ -171,7 +171,7 @@ export const CLOUDFRONT_DEFAULT_SECURITY_POLICY_TLS_V1_2_2021 = '@aws-cdk/aws-cl export const TARGET_PARTITIONS = '@aws-cdk/core:target-partitions'; /** - * This map includes context keys and values for feature flags that enable + * This map includes context keys and values for feature flags that enable * capabilities "from the future", which we could not introduce as the default * behavior due to backwards compatibility for existing projects. * From 8042efe57d338d855359396b7e3b4fef21f7cb7e Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Mon, 13 Dec 2021 13:44:46 +0100 Subject: [PATCH 07/24] Rename regions -> partitions --- packages/@aws-cdk/core/lib/stack.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/@aws-cdk/core/lib/stack.ts b/packages/@aws-cdk/core/lib/stack.ts index ee8d97d3a4ae1..56b407ceba4ac 100644 --- a/packages/@aws-cdk/core/lib/stack.ts +++ b/packages/@aws-cdk/core/lib/stack.ts @@ -831,12 +831,12 @@ export class Stack extends CoreConstruct implements ITaggable { return ret; } - const regions = Node.of(this).tryGetContext(cxapi.TARGET_PARTITIONS); - if (regions !== undefined && !Array.isArray(regions)) { + const partitions = Node.of(this).tryGetContext(cxapi.TARGET_PARTITIONS); + if (partitions !== undefined && !Array.isArray(partitions)) { throw new Error(`Context value '${cxapi.TARGET_PARTITIONS}' should be a list of strings, got: ${JSON.stringify(cxapi.TARGET_PARTITIONS)}`); } - const lookupMap = regions ? RegionInfo.limitedRegionMap(factName, regions) : RegionInfo.regionMap(factName); + const lookupMap = partitions ? RegionInfo.limitedRegionMap(factName, partitions) : RegionInfo.regionMap(factName); const lookupValues = Object.values(lookupMap); // If there are no lookups, just return the default From 69f2ed4270a2492d34d952933f4eecdf69b01174 Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Mon, 13 Dec 2021 13:59:41 +0100 Subject: [PATCH 08/24] Try to match patterns if we can --- .../core/lib/private/region-lookup.ts | 75 +++++++++++++++++++ packages/@aws-cdk/core/lib/stack.ts | 48 +----------- packages/@aws-cdk/cx-api/lib/features.ts | 10 ++- packages/aws-cdk/lib/init.ts | 1 + 4 files changed, 87 insertions(+), 47 deletions(-) create mode 100644 packages/@aws-cdk/core/lib/private/region-lookup.ts diff --git a/packages/@aws-cdk/core/lib/private/region-lookup.ts b/packages/@aws-cdk/core/lib/private/region-lookup.ts new file mode 100644 index 0000000000000..741d34ce2010d --- /dev/null +++ b/packages/@aws-cdk/core/lib/private/region-lookup.ts @@ -0,0 +1,75 @@ +import * as cxapi from '@aws-cdk/cx-api'; +import { RegionInfo } from '@aws-cdk/region-info'; +import { CfnMapping } from '../cfn-mapping'; +import { Aws } from '../cfn-pseudo'; +import { Stack } from '../stack'; + +/** + * Make sure a CfnMapping exists in the given stack with the lookup values for the given fact + * + * Add to an existing CfnMapping if possible. + */ +export function deployTimeLookup(stack: Stack, factName: string, lookupMap: Record) { + // If there are no lookups, just return the default + if (Object.values(lookupMap).length === 0) { + throw new Error(`region-info: don't have any information for ${factName}. Use 'Fact.register' to provide values, or add partitions to the '${cxapi.TARGET_PARTITIONS}' context value.`); + } + + // If the tokenized representation of all values is the same, we can just + // return the value directly and don't need to produce an actual map. + const tokenizedValues = Object.values(tokenizedMap(lookupMap)); + if (tokenizedValues.every((v) => v === tokenizedValues[0])) { + return tokenizedValues[0]; + } + + // Derive map name and lookup key from the factName, splitting on ':' if it exists + const [factClass, factParam] = factName.includes(':') + ? factName.split(':') + : [factName, 'value'] as const; + + const mapId = `${ucfirst(factClass)}Map`; + const factKey = factParam.replace(/[^a-zA-Z0-9]/g, '_'); + + let mapping = stack.node.tryFindChild(mapId) as CfnMapping | undefined; + if (!mapping) { + mapping = new CfnMapping(stack, mapId); + } + for (const [region, value] of Object.entries(lookupMap)) { + mapping.setValue(region, factKey, value); + } + return mapping.findInMap(Aws.REGION, factKey); +} + +function ucfirst(x: string) { + return `${x.substr(0, 1).toUpperCase()}${x.substr(1)}`; +} + +/** + * Try to detect if all values in the map follow the same pattern + * + * Do this by replacing region and URLSuffix values in the found strings + * with their token variant. If at the end all strings have the same format, + * we can simplify to just the single value. + * + * This wouldn't have been necessary if the region-info library had encoded the + * pattern information instead of the literal values... but let's do it here now. + */ +function tokenizedMap(regionMap: Record): Record { + const ret: Record = {}; + for (const [region, value] of Object.entries(regionMap)) { + let tokenizedValue = value; + + const info = RegionInfo.get(region); + if (info?.domainSuffix) { + tokenizedValue = replaceAll(tokenizedValue, info.domainSuffix, Aws.URL_SUFFIX); + } + tokenizedValue = replaceAll(tokenizedValue, region, Aws.REGION); + + ret[region] = tokenizedValue; + } + return ret; +} + +function replaceAll(x: string, pat: string, replacement: string) { + return x.split(pat).join(replacement); +} diff --git a/packages/@aws-cdk/core/lib/stack.ts b/packages/@aws-cdk/core/lib/stack.ts index 56b407ceba4ac..6f78c5acf5ff3 100644 --- a/packages/@aws-cdk/core/lib/stack.ts +++ b/packages/@aws-cdk/core/lib/stack.ts @@ -837,20 +837,6 @@ export class Stack extends CoreConstruct implements ITaggable { } const lookupMap = partitions ? RegionInfo.limitedRegionMap(factName, partitions) : RegionInfo.regionMap(factName); - const lookupValues = Object.values(lookupMap); - - // If there are no lookups, just return the default - if (lookupValues.length === 0) { - if (!defaultValue) { - throw new Error(`region-info: don't have any information for ${factName}. Use 'Fact.register' to provide values, or add partitions to the '${cxapi.TARGET_PARTITIONS}' context value.`); - } - return defaultValue; - } - - // If all values are the same, we can just return the value directly - if (lookupValues.length > 1 && lookupValues.every((v) => v === lookupValues[0])) { - return lookupValues[0]; - } return deployTimeLookup(this, factName, lookupMap); } @@ -1354,34 +1340,6 @@ export interface ExportValueOptions { readonly name?: string; } -/** - * Make sure a CfnMapping exists in the given stack with the lookup values for the given fact - * - * Add to an existing CfnMapping if possible. - */ -function deployTimeLookup(stack: Stack, factName: string, mapValues: Record) { - // Derive map name and lookup key from the factName, splitting on ':' if it exists - const [factClass, factParam] = factName.includes(':') - ? factName.split(':') - : [factName, 'value'] as const; - - const mapId = `${ucfirst(factClass)}Map`; - const factKey = factParam.replace(/[^a-zA-Z0-9]/g, '_'); - - let mapping = stack.node.tryFindChild(mapId) as CfnMapping | undefined; - if (!mapping) { - mapping = new CfnMapping(stack, mapId); - } - for (const [region, value] of Object.entries(mapValues)) { - mapping.setValue(region, factKey, value); - } - return mapping.findInMap(Aws.REGION, factKey); -} - -function ucfirst(x: string) { - return `${x.substr(0, 1).toUpperCase()}${x.substr(1)}`; -} - // These imports have to be at the end to prevent circular imports import { CfnOutput } from './cfn-output'; import { addDependency } from './deps'; @@ -1393,6 +1351,6 @@ import { DefaultStackSynthesizer, IStackSynthesizer, LegacyStackSynthesizer } fr import { Stage } from './stage'; import { ITaggable, TagManager } from './tag-manager'; import { Token, Tokenization } from './token'; -import { referenceNestedStackValueInParent } from './private/refs';import { Fact, RegionInfo } from '@aws-cdk/region-info'; -import { CfnMapping } from './cfn-mapping'; - +import { referenceNestedStackValueInParent } from './private/refs'; +import { Fact, RegionInfo } from '@aws-cdk/region-info'; +import { deployTimeLookup } from './private/region-lookup'; diff --git a/packages/@aws-cdk/cx-api/lib/features.ts b/packages/@aws-cdk/cx-api/lib/features.ts index 136de413f2c51..74f4ff63082a6 100644 --- a/packages/@aws-cdk/cx-api/lib/features.ts +++ b/packages/@aws-cdk/cx-api/lib/features.ts @@ -183,7 +183,7 @@ export const TARGET_PARTITIONS = '@aws-cdk/core:target-partitions'; * * Tests must cover the default (disabled) case and the future (enabled) case. */ -export const FUTURE_FLAGS: { [key: string]: any } = { +export const FUTURE_FLAGS: { [key: string]: boolean } = { [APIGATEWAY_USAGEPLANKEY_ORDERINSENSITIVE_ID]: true, [ENABLE_STACK_NAME_DUPLICATES_CONTEXT]: true, [ENABLE_DIFF_NO_FAIL_CONTEXT]: true, @@ -197,12 +197,18 @@ export const FUTURE_FLAGS: { [key: string]: any } = { [EFS_DEFAULT_ENCRYPTION_AT_REST]: true, [LAMBDA_RECOGNIZE_VERSION_PROPS]: true, [CLOUDFRONT_DEFAULT_SECURITY_POLICY_TLS_V1_2_2021]: true, - [TARGET_PARTITIONS]: ['aws', 'aws-cn'], // We will advertise this flag when the feature is complete // [NEW_STYLE_STACK_SYNTHESIS_CONTEXT]: 'true', }; +/** + * Values that will be set by default in a new project, which are not necessarily booleans (and don't expire) + */ +export const NEW_PROJECT_DEFAULT_CONTEXT: { [key: string]: any} = { + [TARGET_PARTITIONS]: ['aws', 'aws-cn'], +}; + /** * The list of future flags that are now expired. This is going to be used to identify * and block usages of old feature flags in the new major version of CDK. diff --git a/packages/aws-cdk/lib/init.ts b/packages/aws-cdk/lib/init.ts index 1165018a9b469..6570931c12c68 100644 --- a/packages/aws-cdk/lib/init.ts +++ b/packages/aws-cdk/lib/init.ts @@ -191,6 +191,7 @@ export class InitTemplate { config.context = { ...config.context, ...futureFlags, + ...cxapi.NEW_PROJECT_DEFAULT_CONTEXT, }; await fs.writeJson(cdkJson, config, { spaces: 2 }); From 05438e65927573c05f61f716dd60d7782fbf8f24 Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Mon, 13 Dec 2021 14:05:00 +0100 Subject: [PATCH 09/24] Add defaultValue for principals we don't have exceptions for --- packages/@aws-cdk/core/lib/private/region-lookup.ts | 7 +++++-- packages/@aws-cdk/core/lib/stack.ts | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/@aws-cdk/core/lib/private/region-lookup.ts b/packages/@aws-cdk/core/lib/private/region-lookup.ts index 741d34ce2010d..fef4bc26f53a0 100644 --- a/packages/@aws-cdk/core/lib/private/region-lookup.ts +++ b/packages/@aws-cdk/core/lib/private/region-lookup.ts @@ -9,10 +9,13 @@ import { Stack } from '../stack'; * * Add to an existing CfnMapping if possible. */ -export function deployTimeLookup(stack: Stack, factName: string, lookupMap: Record) { +export function deployTimeLookup(stack: Stack, factName: string, lookupMap: Record, defaultValue?: string) { // If there are no lookups, just return the default if (Object.values(lookupMap).length === 0) { - throw new Error(`region-info: don't have any information for ${factName}. Use 'Fact.register' to provide values, or add partitions to the '${cxapi.TARGET_PARTITIONS}' context value.`); + if (defaultValue === undefined) { + throw new Error(`region-info: don't have any information for ${factName}. Use 'Fact.register' to provide values, or add partitions to the '${cxapi.TARGET_PARTITIONS}' context value.`); + } + return defaultValue; } // If the tokenized representation of all values is the same, we can just diff --git a/packages/@aws-cdk/core/lib/stack.ts b/packages/@aws-cdk/core/lib/stack.ts index 6f78c5acf5ff3..6117a9a19e972 100644 --- a/packages/@aws-cdk/core/lib/stack.ts +++ b/packages/@aws-cdk/core/lib/stack.ts @@ -838,7 +838,7 @@ export class Stack extends CoreConstruct implements ITaggable { const lookupMap = partitions ? RegionInfo.limitedRegionMap(factName, partitions) : RegionInfo.regionMap(factName); - return deployTimeLookup(this, factName, lookupMap); + return deployTimeLookup(this, factName, lookupMap, defaultValue); } From ebb6470ced57d7f31511e7154a1239c3f18a1ae4 Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Mon, 13 Dec 2021 14:49:04 +0100 Subject: [PATCH 10/24] Fix Lambda Insights tests --- ...nteg.lambda-insights-mapping.expected.json | 247 +++--------- .../aws-lambda/test/lambda-insights.test.ts | 369 +++++++++--------- .../core/lib/private/region-lookup.ts | 50 ++- 3 files changed, 277 insertions(+), 389 deletions(-) diff --git a/packages/@aws-cdk/aws-lambda/test/integ.lambda-insights-mapping.expected.json b/packages/@aws-cdk/aws-lambda/test/integ.lambda-insights-mapping.expected.json index 7c6fabf1b1fa2..f6cf922db74bf 100644 --- a/packages/@aws-cdk/aws-lambda/test/integ.lambda-insights-mapping.expected.json +++ b/packages/@aws-cdk/aws-lambda/test/integ.lambda-insights-mapping.expected.json @@ -58,12 +58,15 @@ "Handler": "index.handler", "Layers": [ { - "Fn::FindInMap": [ - "LambdaInsightsVersions10540", - { - "Ref": "AWS::Region" - }, - "arn" + "Fn::Join": [ + "", + [ + "arn:aws:lambda:", + { + "Ref": "AWS::Region" + }, + ":580247275435:layer:LambdaInsightsExtension:2" + ] ] } ], @@ -131,12 +134,15 @@ "Handler": "index.handler", "Layers": [ { - "Fn::FindInMap": [ - "LambdaInsightsVersions10860", - { - "Ref": "AWS::Region" - }, - "arn" + "Fn::Join": [ + "", + [ + "arn:aws:lambda:", + { + "Ref": "AWS::Region" + }, + ":580247275435:layer:LambdaInsightsExtension:11" + ] ] } ], @@ -204,12 +210,15 @@ "Handler": "index.handler", "Layers": [ { - "Fn::FindInMap": [ - "LambdaInsightsVersions10890", - { - "Ref": "AWS::Region" - }, - "arn" + "Fn::Join": [ + "", + [ + "arn:aws:lambda:", + { + "Ref": "AWS::Region" + }, + ":580247275435:layer:LambdaInsightsExtension:12" + ] ] } ], @@ -278,11 +287,11 @@ "Layers": [ { "Fn::FindInMap": [ - "LambdaInsightsVersions10980", + "CloudwatchlambdainsightsversionMap", { "Ref": "AWS::Region" }, - "arn" + "1_0_98_0" ] } ], @@ -294,222 +303,66 @@ } }, "Mappings": { - "LambdaInsightsVersions10540": { - "ap-northeast-1": { - "arn": "arn:aws:lambda:ap-northeast-1:580247275435:layer:LambdaInsightsExtension:2" - }, - "ap-northeast-2": { - "arn": "arn:aws:lambda:ap-northeast-2:580247275435:layer:LambdaInsightsExtension:2" - }, - "ap-south-1": { - "arn": "arn:aws:lambda:ap-south-1:580247275435:layer:LambdaInsightsExtension:2" - }, - "ap-southeast-1": { - "arn": "arn:aws:lambda:ap-southeast-1:580247275435:layer:LambdaInsightsExtension:2" - }, - "ap-southeast-2": { - "arn": "arn:aws:lambda:ap-southeast-2:580247275435:layer:LambdaInsightsExtension:2" - }, - "ca-central-1": { - "arn": "arn:aws:lambda:ca-central-1:580247275435:layer:LambdaInsightsExtension:2" - }, - "eu-central-1": { - "arn": "arn:aws:lambda:eu-central-1:580247275435:layer:LambdaInsightsExtension:2" - }, - "eu-north-1": { - "arn": "arn:aws:lambda:eu-north-1:580247275435:layer:LambdaInsightsExtension:2" - }, - "eu-west-1": { - "arn": "arn:aws:lambda:eu-west-1:580247275435:layer:LambdaInsightsExtension:2" - }, - "eu-west-2": { - "arn": "arn:aws:lambda:eu-west-2:580247275435:layer:LambdaInsightsExtension:2" - }, - "eu-west-3": { - "arn": "arn:aws:lambda:eu-west-3:580247275435:layer:LambdaInsightsExtension:2" - }, - "sa-east-1": { - "arn": "arn:aws:lambda:sa-east-1:580247275435:layer:LambdaInsightsExtension:2" - }, - "us-east-1": { - "arn": "arn:aws:lambda:us-east-1:580247275435:layer:LambdaInsightsExtension:2" - }, - "us-east-2": { - "arn": "arn:aws:lambda:us-east-2:580247275435:layer:LambdaInsightsExtension:2" - }, - "us-west-1": { - "arn": "arn:aws:lambda:us-west-1:580247275435:layer:LambdaInsightsExtension:2" - }, - "us-west-2": { - "arn": "arn:aws:lambda:us-west-2:580247275435:layer:LambdaInsightsExtension:2" - } - }, - "LambdaInsightsVersions10860": { - "ap-northeast-1": { - "arn": "arn:aws:lambda:ap-northeast-1:580247275435:layer:LambdaInsightsExtension:11" - }, - "ap-northeast-2": { - "arn": "arn:aws:lambda:ap-northeast-2:580247275435:layer:LambdaInsightsExtension:11" - }, - "ap-south-1": { - "arn": "arn:aws:lambda:ap-south-1:580247275435:layer:LambdaInsightsExtension:11" - }, - "ap-southeast-1": { - "arn": "arn:aws:lambda:ap-southeast-1:580247275435:layer:LambdaInsightsExtension:11" - }, - "ap-southeast-2": { - "arn": "arn:aws:lambda:ap-southeast-2:580247275435:layer:LambdaInsightsExtension:11" - }, - "ca-central-1": { - "arn": "arn:aws:lambda:ca-central-1:580247275435:layer:LambdaInsightsExtension:11" - }, - "eu-central-1": { - "arn": "arn:aws:lambda:eu-central-1:580247275435:layer:LambdaInsightsExtension:11" - }, - "eu-north-1": { - "arn": "arn:aws:lambda:eu-north-1:580247275435:layer:LambdaInsightsExtension:11" - }, - "eu-west-1": { - "arn": "arn:aws:lambda:eu-west-1:580247275435:layer:LambdaInsightsExtension:11" - }, - "eu-west-2": { - "arn": "arn:aws:lambda:eu-west-2:580247275435:layer:LambdaInsightsExtension:11" - }, - "eu-west-3": { - "arn": "arn:aws:lambda:eu-west-3:580247275435:layer:LambdaInsightsExtension:11" - }, - "sa-east-1": { - "arn": "arn:aws:lambda:sa-east-1:580247275435:layer:LambdaInsightsExtension:11" - }, - "us-east-1": { - "arn": "arn:aws:lambda:us-east-1:580247275435:layer:LambdaInsightsExtension:11" - }, - "us-east-2": { - "arn": "arn:aws:lambda:us-east-2:580247275435:layer:LambdaInsightsExtension:11" - }, - "us-west-1": { - "arn": "arn:aws:lambda:us-west-1:580247275435:layer:LambdaInsightsExtension:11" - }, - "us-west-2": { - "arn": "arn:aws:lambda:us-west-2:580247275435:layer:LambdaInsightsExtension:11" - } - }, - "LambdaInsightsVersions10890": { - "ap-northeast-1": { - "arn": "arn:aws:lambda:ap-northeast-1:580247275435:layer:LambdaInsightsExtension:12" - }, - "ap-northeast-2": { - "arn": "arn:aws:lambda:ap-northeast-2:580247275435:layer:LambdaInsightsExtension:12" - }, - "ap-south-1": { - "arn": "arn:aws:lambda:ap-south-1:580247275435:layer:LambdaInsightsExtension:12" - }, - "ap-southeast-1": { - "arn": "arn:aws:lambda:ap-southeast-1:580247275435:layer:LambdaInsightsExtension:12" - }, - "ap-southeast-2": { - "arn": "arn:aws:lambda:ap-southeast-2:580247275435:layer:LambdaInsightsExtension:12" - }, - "ca-central-1": { - "arn": "arn:aws:lambda:ca-central-1:580247275435:layer:LambdaInsightsExtension:12" - }, - "eu-central-1": { - "arn": "arn:aws:lambda:eu-central-1:580247275435:layer:LambdaInsightsExtension:12" - }, - "eu-north-1": { - "arn": "arn:aws:lambda:eu-north-1:580247275435:layer:LambdaInsightsExtension:12" - }, - "eu-west-1": { - "arn": "arn:aws:lambda:eu-west-1:580247275435:layer:LambdaInsightsExtension:12" - }, - "eu-west-2": { - "arn": "arn:aws:lambda:eu-west-2:580247275435:layer:LambdaInsightsExtension:12" - }, - "eu-west-3": { - "arn": "arn:aws:lambda:eu-west-3:580247275435:layer:LambdaInsightsExtension:12" - }, - "sa-east-1": { - "arn": "arn:aws:lambda:sa-east-1:580247275435:layer:LambdaInsightsExtension:12" - }, - "us-east-1": { - "arn": "arn:aws:lambda:us-east-1:580247275435:layer:LambdaInsightsExtension:12" - }, - "us-east-2": { - "arn": "arn:aws:lambda:us-east-2:580247275435:layer:LambdaInsightsExtension:12" - }, - "us-west-1": { - "arn": "arn:aws:lambda:us-west-1:580247275435:layer:LambdaInsightsExtension:12" - }, - "us-west-2": { - "arn": "arn:aws:lambda:us-west-2:580247275435:layer:LambdaInsightsExtension:12" - } - }, - "LambdaInsightsVersions10980": { + "CloudwatchlambdainsightsversionMap": { "af-south-1": { - "arn": "arn:aws:lambda:af-south-1:012438385374:layer:LambdaInsightsExtension:8" + "1_0_98_0": "arn:aws:lambda:af-south-1:012438385374:layer:LambdaInsightsExtension:8" }, "ap-east-1": { - "arn": "arn:aws:lambda:ap-east-1:519774774795:layer:LambdaInsightsExtension:8" + "1_0_98_0": "arn:aws:lambda:ap-east-1:519774774795:layer:LambdaInsightsExtension:8" }, "ap-northeast-1": { - "arn": "arn:aws:lambda:ap-northeast-1:580247275435:layer:LambdaInsightsExtension:14" + "1_0_98_0": "arn:aws:lambda:ap-northeast-1:580247275435:layer:LambdaInsightsExtension:14" }, "ap-northeast-2": { - "arn": "arn:aws:lambda:ap-northeast-2:580247275435:layer:LambdaInsightsExtension:14" + "1_0_98_0": "arn:aws:lambda:ap-northeast-2:580247275435:layer:LambdaInsightsExtension:14" }, "ap-south-1": { - "arn": "arn:aws:lambda:ap-south-1:580247275435:layer:LambdaInsightsExtension:14" + "1_0_98_0": "arn:aws:lambda:ap-south-1:580247275435:layer:LambdaInsightsExtension:14" }, "ap-southeast-1": { - "arn": "arn:aws:lambda:ap-southeast-1:580247275435:layer:LambdaInsightsExtension:14" + "1_0_98_0": "arn:aws:lambda:ap-southeast-1:580247275435:layer:LambdaInsightsExtension:14" }, "ap-southeast-2": { - "arn": "arn:aws:lambda:ap-southeast-2:580247275435:layer:LambdaInsightsExtension:14" + "1_0_98_0": "arn:aws:lambda:ap-southeast-2:580247275435:layer:LambdaInsightsExtension:14" }, "ca-central-1": { - "arn": "arn:aws:lambda:ca-central-1:580247275435:layer:LambdaInsightsExtension:14" - }, - "cn-north-1": { - "arn": "arn:aws-cn:lambda:cn-north-1:488211338238:layer:LambdaInsightsExtension:8" - }, - "cn-northwest-1": { - "arn": "arn:aws-cn:lambda:cn-northwest-1:488211338238:layer:LambdaInsightsExtension:8" + "1_0_98_0": "arn:aws:lambda:ca-central-1:580247275435:layer:LambdaInsightsExtension:14" }, "eu-central-1": { - "arn": "arn:aws:lambda:eu-central-1:580247275435:layer:LambdaInsightsExtension:14" + "1_0_98_0": "arn:aws:lambda:eu-central-1:580247275435:layer:LambdaInsightsExtension:14" }, "eu-north-1": { - "arn": "arn:aws:lambda:eu-north-1:580247275435:layer:LambdaInsightsExtension:14" + "1_0_98_0": "arn:aws:lambda:eu-north-1:580247275435:layer:LambdaInsightsExtension:14" }, "eu-south-1": { - "arn": "arn:aws:lambda:eu-south-1:339249233099:layer:LambdaInsightsExtension:8" + "1_0_98_0": "arn:aws:lambda:eu-south-1:339249233099:layer:LambdaInsightsExtension:8" }, "eu-west-1": { - "arn": "arn:aws:lambda:eu-west-1:580247275435:layer:LambdaInsightsExtension:14" + "1_0_98_0": "arn:aws:lambda:eu-west-1:580247275435:layer:LambdaInsightsExtension:14" }, "eu-west-2": { - "arn": "arn:aws:lambda:eu-west-2:580247275435:layer:LambdaInsightsExtension:14" + "1_0_98_0": "arn:aws:lambda:eu-west-2:580247275435:layer:LambdaInsightsExtension:14" }, "eu-west-3": { - "arn": "arn:aws:lambda:eu-west-3:580247275435:layer:LambdaInsightsExtension:14" + "1_0_98_0": "arn:aws:lambda:eu-west-3:580247275435:layer:LambdaInsightsExtension:14" }, "me-south-1": { - "arn": "arn:aws:lambda:me-south-1:285320876703:layer:LambdaInsightsExtension:8" + "1_0_98_0": "arn:aws:lambda:me-south-1:285320876703:layer:LambdaInsightsExtension:8" }, "sa-east-1": { - "arn": "arn:aws:lambda:sa-east-1:580247275435:layer:LambdaInsightsExtension:14" + "1_0_98_0": "arn:aws:lambda:sa-east-1:580247275435:layer:LambdaInsightsExtension:14" }, "us-east-1": { - "arn": "arn:aws:lambda:us-east-1:580247275435:layer:LambdaInsightsExtension:14" + "1_0_98_0": "arn:aws:lambda:us-east-1:580247275435:layer:LambdaInsightsExtension:14" }, "us-east-2": { - "arn": "arn:aws:lambda:us-east-2:580247275435:layer:LambdaInsightsExtension:14" + "1_0_98_0": "arn:aws:lambda:us-east-2:580247275435:layer:LambdaInsightsExtension:14" }, "us-west-1": { - "arn": "arn:aws:lambda:us-west-1:580247275435:layer:LambdaInsightsExtension:14" + "1_0_98_0": "arn:aws:lambda:us-west-1:580247275435:layer:LambdaInsightsExtension:14" }, "us-west-2": { - "arn": "arn:aws:lambda:us-west-2:580247275435:layer:LambdaInsightsExtension:14" + "1_0_98_0": "arn:aws:lambda:us-west-2:580247275435:layer:LambdaInsightsExtension:14" } } } diff --git a/packages/@aws-cdk/aws-lambda/test/lambda-insights.test.ts b/packages/@aws-cdk/aws-lambda/test/lambda-insights.test.ts index 762df158da6f4..81465daafdcb4 100644 --- a/packages/@aws-cdk/aws-lambda/test/lambda-insights.test.ts +++ b/packages/@aws-cdk/aws-lambda/test/lambda-insights.test.ts @@ -81,17 +81,17 @@ describe('lambda-insights', () => { const app = new cdk.App(); const stack = new cdk.Stack(app, 'Stack', {}); - functionWithInsightsVersion(stack, 'MyLambda', lambda.LambdaInsightsVersion.VERSION_1_0_54_0); + functionWithInsightsVersion(stack, 'MyLambda', lambda.LambdaInsightsVersion.VERSION_1_0_98_0); - // Should be looking up a mapping + // Still resolves because all elements of the mapping map to the same value expect(stack).toHaveResource('AWS::Lambda::Function', { Layers: [{ 'Fn::FindInMap': [ - 'LambdaInsightsVersions10540', + 'CloudwatchlambdainsightsversionMap', { Ref: 'AWS::Region', }, - 'arn', + '1_0_98_0', ], }], }); @@ -105,212 +105,223 @@ describe('lambda-insights', () => { const app = new cdk.App(); const stack = new cdk.Stack(app, 'Stack', {}); - functionWithInsightsVersion(stack, 'MyLambda1', lambda.LambdaInsightsVersion.VERSION_1_0_54_0); - functionWithInsightsVersion(stack, 'MyLambda2', lambda.LambdaInsightsVersion.VERSION_1_0_54_0); + functionWithInsightsVersion(stack, 'MyLambda1', lambda.LambdaInsightsVersion.VERSION_1_0_98_0); + functionWithInsightsVersion(stack, 'MyLambda2', lambda.LambdaInsightsVersion.VERSION_1_0_98_0); /* eslint-disable quote-props */ - expect(stack).toMatchTemplate({ - Resources: { - MyLambda1ServiceRole69A7E1EA: { - 'Type': 'AWS::IAM::Role', - 'Properties': { - 'AssumeRolePolicyDocument': { - 'Statement': [ - { - 'Action': 'sts:AssumeRole', - 'Effect': 'Allow', - 'Principal': { - 'Service': 'lambda.amazonaws.com', + expect(stack).toMatchTemplate( + { + Resources: { + MyLambda1ServiceRole69A7E1EA: { + Type: 'AWS::IAM::Role', + Properties: { + AssumeRolePolicyDocument: { + Statement: [ + { + Action: 'sts:AssumeRole', + Effect: 'Allow', + Principal: { + Service: 'lambda.amazonaws.com', + }, }, + ], + Version: '2012-10-17', + }, + ManagedPolicyArns: [ + { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':iam::aws:policy/service-role/AWSLambdaBasicExecutionRole', + ], + ], + }, + { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':iam::aws:policy/CloudWatchLambdaInsightsExecutionRolePolicy', + ], + ], }, ], - 'Version': '2012-10-17', }, - 'ManagedPolicyArns': [ - { - 'Fn::Join': [ - '', - [ - 'arn:', - { - 'Ref': 'AWS::Partition', - }, - ':iam::aws:policy/service-role/AWSLambdaBasicExecutionRole', - ], - ], + }, + MyLambda1AAFB4554: { + Type: 'AWS::Lambda::Function', + Properties: { + Code: { + ZipFile: 'foo', }, - { - 'Fn::Join': [ - '', - [ - 'arn:', + Role: { + 'Fn::GetAtt': ['MyLambda1ServiceRole69A7E1EA', 'Arn'], + }, + Handler: 'index.handler', + Layers: [ + { + 'Fn::FindInMap': [ + 'CloudwatchlambdainsightsversionMap', { - 'Ref': 'AWS::Partition', + Ref: 'AWS::Region', }, - ':iam::aws:policy/CloudWatchLambdaInsightsExecutionRolePolicy', + '1_0_98_0', ], - ], - }, - ], - }, - }, - MyLambda1AAFB4554: { - 'Type': 'AWS::Lambda::Function', - 'Properties': { - 'Code': { - 'ZipFile': 'foo', - }, - 'Role': { - 'Fn::GetAtt': [ - 'MyLambda1ServiceRole69A7E1EA', - 'Arn', + }, ], + Runtime: 'nodejs10.x', }, - 'Handler': 'index.handler', - 'Layers': [ - { - 'Fn::FindInMap': [ - 'LambdaInsightsVersions10540', + DependsOn: ['MyLambda1ServiceRole69A7E1EA'], + }, + MyLambda2ServiceRoleD09B370C: { + Type: 'AWS::IAM::Role', + Properties: { + AssumeRolePolicyDocument: { + Statement: [ { - 'Ref': 'AWS::Region', + Action: 'sts:AssumeRole', + Effect: 'Allow', + Principal: { + Service: 'lambda.amazonaws.com', + }, }, - 'arn', ], + Version: '2012-10-17', }, - ], - 'Runtime': 'nodejs10.x', - }, - 'DependsOn': [ - 'MyLambda1ServiceRole69A7E1EA', - ], - }, - MyLambda2ServiceRoleD09B370C: { - 'Type': 'AWS::IAM::Role', - 'Properties': { - 'AssumeRolePolicyDocument': { - 'Statement': [ + ManagedPolicyArns: [ { - 'Action': 'sts:AssumeRole', - 'Effect': 'Allow', - 'Principal': { - 'Service': 'lambda.amazonaws.com', - }, + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':iam::aws:policy/service-role/AWSLambdaBasicExecutionRole', + ], + ], + }, + { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':iam::aws:policy/CloudWatchLambdaInsightsExecutionRolePolicy', + ], + ], }, ], - 'Version': '2012-10-17', }, - 'ManagedPolicyArns': [ - { - 'Fn::Join': [ - '', - [ - 'arn:', - { - 'Ref': 'AWS::Partition', - }, - ':iam::aws:policy/service-role/AWSLambdaBasicExecutionRole', - ], - ], + }, + MyLambda2254B54D5: { + Type: 'AWS::Lambda::Function', + Properties: { + Code: { + ZipFile: 'foo', }, - { - 'Fn::Join': [ - '', - [ - 'arn:', + Role: { + 'Fn::GetAtt': ['MyLambda2ServiceRoleD09B370C', 'Arn'], + }, + Handler: 'index.handler', + Layers: [ + { + 'Fn::FindInMap': [ + 'CloudwatchlambdainsightsversionMap', { - 'Ref': 'AWS::Partition', + Ref: 'AWS::Region', }, - ':iam::aws:policy/CloudWatchLambdaInsightsExecutionRolePolicy', + '1_0_98_0', ], - ], - }, - ], - }, - }, - MyLambda2254B54D5: { - 'Type': 'AWS::Lambda::Function', - 'Properties': { - 'Code': { - 'ZipFile': 'foo', - }, - 'Role': { - 'Fn::GetAtt': [ - 'MyLambda2ServiceRoleD09B370C', - 'Arn', + }, ], + Runtime: 'nodejs10.x', }, - 'Handler': 'index.handler', - 'Layers': [ - { - 'Fn::FindInMap': [ - 'LambdaInsightsVersions10540', - { - 'Ref': 'AWS::Region', - }, - 'arn', - ], - }, - ], - 'Runtime': 'nodejs10.x', + DependsOn: ['MyLambda2ServiceRoleD09B370C'], }, - 'DependsOn': [ - 'MyLambda2ServiceRoleD09B370C', - ], }, - }, - Mappings: { - LambdaInsightsVersions10540: { - 'ap-northeast-1': { - arn: 'arn:aws:lambda:ap-northeast-1:580247275435:layer:LambdaInsightsExtension:2', - }, - 'ap-northeast-2': { - 'arn': 'arn:aws:lambda:ap-northeast-2:580247275435:layer:LambdaInsightsExtension:2', - }, - 'ap-south-1': { - 'arn': 'arn:aws:lambda:ap-south-1:580247275435:layer:LambdaInsightsExtension:2', - }, - 'ap-southeast-1': { - 'arn': 'arn:aws:lambda:ap-southeast-1:580247275435:layer:LambdaInsightsExtension:2', - }, - 'ap-southeast-2': { - 'arn': 'arn:aws:lambda:ap-southeast-2:580247275435:layer:LambdaInsightsExtension:2', - }, - 'ca-central-1': { - 'arn': 'arn:aws:lambda:ca-central-1:580247275435:layer:LambdaInsightsExtension:2', - }, - 'eu-central-1': { - 'arn': 'arn:aws:lambda:eu-central-1:580247275435:layer:LambdaInsightsExtension:2', - }, - 'eu-north-1': { - 'arn': 'arn:aws:lambda:eu-north-1:580247275435:layer:LambdaInsightsExtension:2', - }, - 'eu-west-1': { - 'arn': 'arn:aws:lambda:eu-west-1:580247275435:layer:LambdaInsightsExtension:2', - }, - 'eu-west-2': { - 'arn': 'arn:aws:lambda:eu-west-2:580247275435:layer:LambdaInsightsExtension:2', - }, - 'eu-west-3': { - 'arn': 'arn:aws:lambda:eu-west-3:580247275435:layer:LambdaInsightsExtension:2', - }, - 'sa-east-1': { - 'arn': 'arn:aws:lambda:sa-east-1:580247275435:layer:LambdaInsightsExtension:2', - }, - 'us-east-1': { - 'arn': 'arn:aws:lambda:us-east-1:580247275435:layer:LambdaInsightsExtension:2', - }, - 'us-east-2': { - 'arn': 'arn:aws:lambda:us-east-2:580247275435:layer:LambdaInsightsExtension:2', - }, - 'us-west-1': { - 'arn': 'arn:aws:lambda:us-west-1:580247275435:layer:LambdaInsightsExtension:2', - }, - 'us-west-2': { - 'arn': 'arn:aws:lambda:us-west-2:580247275435:layer:LambdaInsightsExtension:2', + Mappings: { + CloudwatchlambdainsightsversionMap: { + 'af-south-1': { + '1_0_98_0': 'arn:aws:lambda:af-south-1:012438385374:layer:LambdaInsightsExtension:8', + }, + 'ap-east-1': { + '1_0_98_0': 'arn:aws:lambda:ap-east-1:519774774795:layer:LambdaInsightsExtension:8', + }, + 'ap-northeast-1': { + '1_0_98_0': 'arn:aws:lambda:ap-northeast-1:580247275435:layer:LambdaInsightsExtension:14', + }, + 'ap-northeast-2': { + '1_0_98_0': 'arn:aws:lambda:ap-northeast-2:580247275435:layer:LambdaInsightsExtension:14', + }, + 'ap-south-1': { + '1_0_98_0': 'arn:aws:lambda:ap-south-1:580247275435:layer:LambdaInsightsExtension:14', + }, + 'ap-southeast-1': { + '1_0_98_0': 'arn:aws:lambda:ap-southeast-1:580247275435:layer:LambdaInsightsExtension:14', + }, + 'ap-southeast-2': { + '1_0_98_0': 'arn:aws:lambda:ap-southeast-2:580247275435:layer:LambdaInsightsExtension:14', + }, + 'ca-central-1': { + '1_0_98_0': 'arn:aws:lambda:ca-central-1:580247275435:layer:LambdaInsightsExtension:14', + }, + 'cn-north-1': { + '1_0_98_0': 'arn:aws-cn:lambda:cn-north-1:488211338238:layer:LambdaInsightsExtension:8', + }, + 'cn-northwest-1': { + '1_0_98_0': 'arn:aws-cn:lambda:cn-northwest-1:488211338238:layer:LambdaInsightsExtension:8', + }, + 'eu-central-1': { + '1_0_98_0': 'arn:aws:lambda:eu-central-1:580247275435:layer:LambdaInsightsExtension:14', + }, + 'eu-north-1': { + '1_0_98_0': 'arn:aws:lambda:eu-north-1:580247275435:layer:LambdaInsightsExtension:14', + }, + 'eu-south-1': { + '1_0_98_0': 'arn:aws:lambda:eu-south-1:339249233099:layer:LambdaInsightsExtension:8', + }, + 'eu-west-1': { + '1_0_98_0': 'arn:aws:lambda:eu-west-1:580247275435:layer:LambdaInsightsExtension:14', + }, + 'eu-west-2': { + '1_0_98_0': 'arn:aws:lambda:eu-west-2:580247275435:layer:LambdaInsightsExtension:14', + }, + 'eu-west-3': { + '1_0_98_0': 'arn:aws:lambda:eu-west-3:580247275435:layer:LambdaInsightsExtension:14', + }, + 'me-south-1': { + '1_0_98_0': 'arn:aws:lambda:me-south-1:285320876703:layer:LambdaInsightsExtension:8', + }, + 'sa-east-1': { + '1_0_98_0': 'arn:aws:lambda:sa-east-1:580247275435:layer:LambdaInsightsExtension:14', + }, + 'us-east-1': { + '1_0_98_0': 'arn:aws:lambda:us-east-1:580247275435:layer:LambdaInsightsExtension:14', + }, + 'us-east-2': { + '1_0_98_0': 'arn:aws:lambda:us-east-2:580247275435:layer:LambdaInsightsExtension:14', + }, + 'us-west-1': { + '1_0_98_0': 'arn:aws:lambda:us-west-1:580247275435:layer:LambdaInsightsExtension:14', + }, + 'us-west-2': { + '1_0_98_0': 'arn:aws:lambda:us-west-2:580247275435:layer:LambdaInsightsExtension:14', + }, }, }, }, - }, MatchStyle.EXACT); + MatchStyle.EXACT + ); // On synthesis it should not throw an error expect(() => app.synth()).not.toThrow(); }); diff --git a/packages/@aws-cdk/core/lib/private/region-lookup.ts b/packages/@aws-cdk/core/lib/private/region-lookup.ts index fef4bc26f53a0..208ff7eee30be 100644 --- a/packages/@aws-cdk/core/lib/private/region-lookup.ts +++ b/packages/@aws-cdk/core/lib/private/region-lookup.ts @@ -20,9 +20,9 @@ export function deployTimeLookup(stack: Stack, factName: string, lookupMap: Reco // If the tokenized representation of all values is the same, we can just // return the value directly and don't need to produce an actual map. - const tokenizedValues = Object.values(tokenizedMap(lookupMap)); - if (tokenizedValues.every((v) => v === tokenizedValues[0])) { - return tokenizedValues[0]; + const pattern = findValuePattern(lookupMap); + if (pattern !== undefined) { + return pattern; } // Derive map name and lookup key from the factName, splitting on ':' if it exists @@ -57,22 +57,46 @@ function ucfirst(x: string) { * This wouldn't have been necessary if the region-info library had encoded the * pattern information instead of the literal values... but let's do it here now. */ -function tokenizedMap(regionMap: Record): Record { - const ret: Record = {}; - for (const [region, value] of Object.entries(regionMap)) { - let tokenizedValue = value; +function findValuePattern(regionMap: Record): string | undefined { + const simplified: Record = { ...regionMap }; - const info = RegionInfo.get(region); - if (info?.domainSuffix) { - tokenizedValue = replaceAll(tokenizedValue, info.domainSuffix, Aws.URL_SUFFIX); + // If they all contain URL_SUFFIX, substitute it, but only if the value is different + // among some values in the list (we don't want to tokenize unnecessarily, i.e. we don't + // want to replace `amazonaws.com` with URL_SUFFIX if it's not necessary) + const urlSuffixes = Object.keys(simplified).map(urlSuffix); + if (!allSame(urlSuffixes) && Object.entries(simplified).every(([region, value]) => value.includes(urlSuffix(region)))) { + for (const region in simplified) { + simplified[region] = replaceAll(simplified[region], urlSuffix(region), Aws.URL_SUFFIX); } - tokenizedValue = replaceAll(tokenizedValue, region, Aws.REGION); + } - ret[region] = tokenizedValue; + // If they all contain REGION, substitute it (no need to do the "is everything different" + // check, this is true by design for these values) + if (Object.entries(simplified).every(([region, value]) => value.includes(region))) { + for (const region in simplified) { + simplified[region] = replaceAll(simplified[region], region, Aws.REGION); + } } - return ret; + + // If the values are now all the same, return the singleton value + const values = Object.values(simplified); + if (allSame(values)) { + return values[0]; + } + + // Otherwise we failed + return undefined; +} + +function allSame(xs: string[]) { + return xs.every((x) => x === xs[0]); +} + +function urlSuffix(region: string) { + return RegionInfo.get(region)?.domainSuffix ?? 'amazonaws.com'; } function replaceAll(x: string, pat: string, replacement: string) { return x.split(pat).join(replacement); } + From 0273b0b2159edb1e63e555eef778757efbd7eac6 Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Mon, 13 Dec 2021 15:13:26 +0100 Subject: [PATCH 11/24] Do the same in CodeBuild --- .../lib/linux-gpu-build-image.ts | 45 +++++++--------- .../@aws-cdk/aws-codebuild/lib/project.ts | 9 ++-- ...arning-container-build-image.expected.json | 52 ++++++++----------- .../aws-lambda/test/lambda-insights.test.ts | 2 +- 4 files changed, 50 insertions(+), 58 deletions(-) diff --git a/packages/@aws-cdk/aws-codebuild/lib/linux-gpu-build-image.ts b/packages/@aws-cdk/aws-codebuild/lib/linux-gpu-build-image.ts index b26611745afbb..921fe672c9bfa 100644 --- a/packages/@aws-cdk/aws-codebuild/lib/linux-gpu-build-image.ts +++ b/packages/@aws-cdk/aws-codebuild/lib/linux-gpu-build-image.ts @@ -1,6 +1,6 @@ import * as ecr from '@aws-cdk/aws-ecr'; import * as core from '@aws-cdk/core'; -import { FactName, RegionInfo } from '@aws-cdk/region-info'; +import { FactName } from '@aws-cdk/region-info'; import { BuildSpec } from './build-spec'; import { runScriptLinuxBuildSpec } from './private/run-script-linux-build-spec'; import { @@ -10,9 +10,7 @@ import { // keep this import separate from other imports to reduce chance for merge conflicts with v2-main // eslint-disable-next-line no-duplicate-imports, import/order -import { Construct } from '@aws-cdk/core'; - -const mappingName = 'AwsDeepLearningContainersRepositoriesAccounts'; +import { Construct, Lazy } from '@aws-cdk/core'; /** * A CodeBuild GPU image running Linux. @@ -109,37 +107,34 @@ export class LinuxGpuBuildImage implements IBindableBuildImage { public readonly type = 'LINUX_GPU_CONTAINER'; public readonly defaultComputeType = ComputeType.LARGE; - public readonly imageId: string; public readonly imagePullPrincipalType?: ImagePullPrincipalType = ImagePullPrincipalType.SERVICE_ROLE; + public readonly imageId: string; - private readonly accountExpression: string; + private _imageId?: string; - private constructor(private readonly repositoryName: string, tag: string, private readonly account: string | undefined) { - this.accountExpression = account ?? core.Fn.findInMap(mappingName, core.Aws.REGION, 'repositoryAccount'); - this.imageId = `${this.accountExpression}.dkr.ecr.${core.Aws.REGION}.${core.Aws.URL_SUFFIX}/${repositoryName}:${tag}`; + private constructor(private readonly repositoryName: string, private readonly tag: string, private readonly account: string | undefined) { + this.imageId = Lazy.string({ + produce: () => { + if (this._imageId === undefined) { + throw new Error('Make sure this \'LinuxGpuBuildImage\' is used in a CodeBuild Project construct'); + } + return this._imageId; + }, + }); } public bind(scope: Construct, project: IProject, _options: BuildImageBindOptions): BuildImageConfig { - if (!this.account) { - const scopeStack = core.Stack.of(scope); - // Unfortunately, the account IDs of the DLC repositories are not the same in all regions. - // Because of that, use a (singleton) Mapping to find the correct account - if (!scopeStack.node.tryFindChild(mappingName)) { - const mapping: { [k1: string]: { [k2: string]: any } } = {}; - // get the accounts from the region-info module - const region2Accounts = RegionInfo.regionMap(FactName.DLC_REPOSITORY_ACCOUNT); - for (const [region, account] of Object.entries(region2Accounts)) { - mapping[region] = { repositoryAccount: account }; - } - new core.CfnMapping(scopeStack, mappingName, { mapping }); - } - } - const repository = ecr.Repository.fromRepositoryAttributes(scope, 'AwsDlcRepositoryCodeBuild', { repositoryName: this.repositoryName, - repositoryArn: ecr.Repository.arnForLocalRepository(this.repositoryName, scope, this.accountExpression), + repositoryArn: ecr.Repository.arnForLocalRepository( + this.repositoryName, + scope, + this.account ?? core.Stack.of(scope).regionalFact(FactName.DLC_REPOSITORY_ACCOUNT), + ), }); + repository.grantPull(project); + this._imageId = repository.repositoryUriForTag(this.tag); return { }; diff --git a/packages/@aws-cdk/aws-codebuild/lib/project.ts b/packages/@aws-cdk/aws-codebuild/lib/project.ts index f7a503d335cbc..c6a816e3aedd2 100644 --- a/packages/@aws-cdk/aws-codebuild/lib/project.ts +++ b/packages/@aws-cdk/aws-codebuild/lib/project.ts @@ -1138,9 +1138,8 @@ export class Project extends ProjectBase { } // bind - const bindFunction = (this.buildImage as any).bind; - if (bindFunction) { - bindFunction.call(this.buildImage, this, this, {}); + if (isBindableBuildImage(this.buildImage)) { + this.buildImage.bind(this, this, {}); } } @@ -2123,3 +2122,7 @@ export enum ProjectNotificationEvents { */ BUILD_PHASE_SUCCEEDED = 'codebuild-project-build-phase-success', } + +function isBindableBuildImage(x: unknown): x is IBindableBuildImage { + return typeof x === 'object' && !!x && !!(x as any).bind; +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-codebuild/test/integ.aws-deep-learning-container-build-image.expected.json b/packages/@aws-cdk/aws-codebuild/test/integ.aws-deep-learning-container-build-image.expected.json index 3551f01dadd54..a926f47c0657d 100644 --- a/packages/@aws-cdk/aws-codebuild/test/integ.aws-deep-learning-container-build-image.expected.json +++ b/packages/@aws-cdk/aws-codebuild/test/integ.aws-deep-learning-container-build-image.expected.json @@ -135,11 +135,11 @@ ":", { "Fn::FindInMap": [ - "AwsDeepLearningContainersRepositoriesAccounts", + "DlcRepositoryAccountMap", { "Ref": "AWS::Region" }, - "repositoryAccount" + "value" ] }, ":repository/mxnet-training" @@ -177,11 +177,11 @@ [ { "Fn::FindInMap": [ - "AwsDeepLearningContainersRepositoriesAccounts", + "DlcRepositoryAccountMap", { "Ref": "AWS::Region" }, - "repositoryAccount" + "value" ] }, ".dkr.ecr.", @@ -215,66 +215,60 @@ } }, "Mappings": { - "AwsDeepLearningContainersRepositoriesAccounts": { + "DlcRepositoryAccountMap": { "ap-east-1": { - "repositoryAccount": "871362719292" + "value": "871362719292" }, "ap-northeast-1": { - "repositoryAccount": "763104351884" + "value": "763104351884" }, "ap-northeast-2": { - "repositoryAccount": "763104351884" + "value": "763104351884" }, "ap-south-1": { - "repositoryAccount": "763104351884" + "value": "763104351884" }, "ap-southeast-1": { - "repositoryAccount": "763104351884" + "value": "763104351884" }, "ap-southeast-2": { - "repositoryAccount": "763104351884" + "value": "763104351884" }, "ca-central-1": { - "repositoryAccount": "763104351884" - }, - "cn-north-1": { - "repositoryAccount": "727897471807" - }, - "cn-northwest-1": { - "repositoryAccount": "727897471807" + "value": "763104351884" }, "eu-central-1": { - "repositoryAccount": "763104351884" + "value": "763104351884" }, "eu-north-1": { - "repositoryAccount": "763104351884" + "value": "763104351884" }, "eu-west-1": { - "repositoryAccount": "763104351884" + "value": "763104351884" }, "eu-west-2": { - "repositoryAccount": "763104351884" + "value": "763104351884" }, "eu-west-3": { - "repositoryAccount": "763104351884" + "value": "763104351884" }, "me-south-1": { - "repositoryAccount": "217643126080" + "value": "217643126080" }, "sa-east-1": { - "repositoryAccount": "763104351884" + "value": "763104351884" }, "us-east-1": { - "repositoryAccount": "763104351884" + "value": "763104351884" }, "us-east-2": { - "repositoryAccount": "763104351884" + "value": "763104351884" }, "us-west-1": { - "repositoryAccount": "763104351884" + "value": "763104351884" }, "us-west-2": { - "repositoryAccount": "763104351884" + "value": "763104351884" } } } diff --git a/packages/@aws-cdk/aws-lambda/test/lambda-insights.test.ts b/packages/@aws-cdk/aws-lambda/test/lambda-insights.test.ts index 81465daafdcb4..0764fd892624d 100644 --- a/packages/@aws-cdk/aws-lambda/test/lambda-insights.test.ts +++ b/packages/@aws-cdk/aws-lambda/test/lambda-insights.test.ts @@ -320,7 +320,7 @@ describe('lambda-insights', () => { }, }, }, - MatchStyle.EXACT + MatchStyle.EXACT, ); // On synthesis it should not throw an error expect(() => app.synth()).not.toThrow(); From 2d3e5c2cd9aad1f105a738f25470b13abc9b5fd5 Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Mon, 13 Dec 2021 15:17:42 +0100 Subject: [PATCH 12/24] Fix tests for CLI --- packages/aws-cdk/test/init.test.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/aws-cdk/test/init.test.ts b/packages/aws-cdk/test/init.test.ts index fe27f114c12c3..bf06892e83b6a 100644 --- a/packages/aws-cdk/test/init.test.ts +++ b/packages/aws-cdk/test/init.test.ts @@ -81,9 +81,10 @@ describe.each(['1', '2'])('v%s tests', (majorVersion) => { const config = await fs.readJson(path.join(tmpDir, 'cdk.json')); const context = config.context || {}; - for (const [key, expected] of Object.entries(context)) { - const actual = cxapi.FUTURE_FLAGS[key]; - expect(actual).toEqual(expected); + for (const [key, actual] of Object.entries(context)) { + expect(key in cxapi.FUTURE_FLAGS || key in cxapi.NEW_PROJECT_DEFAULT_CONTEXT).toBeTruthy(); + + expect(cxapi.FUTURE_FLAGS[key] ?? cxapi.NEW_PROJECT_DEFAULT_CONTEXT[key]).toEqual(actual); } // assert that expired future flags are not part of the cdk.json From 2d6b3e61ad75ca238ad8ddc830dfcbbcfea0bb88 Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Mon, 13 Dec 2021 16:25:16 +0100 Subject: [PATCH 13/24] add tests for regionalFact --- packages/@aws-cdk/core/test/stack.test.ts | 55 +++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/packages/@aws-cdk/core/test/stack.test.ts b/packages/@aws-cdk/core/test/stack.test.ts index 160ff09278b50..b344dbbbff0be 100644 --- a/packages/@aws-cdk/core/test/stack.test.ts +++ b/packages/@aws-cdk/core/test/stack.test.ts @@ -1,10 +1,13 @@ import { testDeprecated, testFutureBehavior, testLegacyBehavior } from '@aws-cdk/cdk-build-tools'; import * as cxapi from '@aws-cdk/cx-api'; +import { Fact } from '@aws-cdk/region-info'; +import { Node } from 'constructs'; import { App, CfnCondition, CfnInclude, CfnOutput, CfnParameter, CfnResource, Construct, Lazy, ScopedAws, Stack, validateString, ISynthesisSession, Tags, LegacyStackSynthesizer, DefaultStackSynthesizer, NestedStack, + Aws, } from '../lib'; import { Intrinsic } from '../lib/private/intrinsic'; import { resolveReferences } from '../lib/private/refs'; @@ -1190,6 +1193,58 @@ describe('stack', () => { }); }); +describe('regionalFact', () => { + Fact.register({ name: 'MyFact', region: 'us-east-1', value: 'x.amazonaws.com' }); + Fact.register({ name: 'MyFact', region: 'eu-west-1', value: 'x.amazonaws.com' }); + Fact.register({ name: 'MyFact', region: 'cn-north-1', value: 'x.amazonaws.com.cn' }); + + Fact.register({ name: 'WeirdFact', region: 'us-east-1', value: 'oneformat' }); + Fact.register({ name: 'WeirdFact', region: 'eu-west-1', value: 'otherformat' }); + + test('regional facts return a literal value if possible', () => { + const stack = new Stack(undefined, 'Stack', { env: { region: 'us-east-1' } }); + expect(stack.regionalFact('MyFact')).toEqual('x.amazonaws.com'); + }); + + test('regional facts are simplified to use URL_SUFFIX token if possible', () => { + const stack = new Stack(); + expect(stack.regionalFact('MyFact')).toEqual(`x.${Aws.URL_SUFFIX}`); + }); + + test('regional facts are simplified to use concrete values if URL_SUFFIX token is not necessary', () => { + const stack = new Stack(); + Node.of(stack).setContext(cxapi.TARGET_PARTITIONS, ['aws']); + expect(stack.regionalFact('MyFact')).toEqual('x.amazonaws.com'); + }); + + test('regional facts generate a mapping if necessary', () => { + const stack = new Stack(); + new CfnOutput(stack, 'TheFact', { + value: stack.regionalFact('WeirdFact'), + }); + + expect(toCloudFormation(stack)).toEqual({ + Mappings: { + WeirdFactMap: { + 'eu-west-1': { value: 'otherformat' }, + 'us-east-1': { value: 'oneformat' }, + }, + }, + Outputs: { + TheFact: { + Value: { + 'Fn::FindInMap': [ + 'WeirdFactMap', + { Ref: 'AWS::Region' }, + 'value', + ], + }, + }, + }, + }); + }); +}); + class StackWithPostProcessor extends Stack { // ... From 962cb22e7d3963f8e27f4df455b1942f87ae83a4 Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Mon, 13 Dec 2021 16:39:28 +0100 Subject: [PATCH 14/24] Mark test as testing a deprecated API --- packages/@aws-cdk/aws-iam/test/policy-document.test.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/@aws-cdk/aws-iam/test/policy-document.test.ts b/packages/@aws-cdk/aws-iam/test/policy-document.test.ts index bf93e31901c6c..ff30531f5fc59 100644 --- a/packages/@aws-cdk/aws-iam/test/policy-document.test.ts +++ b/packages/@aws-cdk/aws-iam/test/policy-document.test.ts @@ -1,4 +1,5 @@ import '@aws-cdk/assert-internal/jest'; +import { testDeprecated } from '@aws-cdk/cdk-build-tools'; import { Lazy, Stack, Token } from '@aws-cdk/core'; import { AccountPrincipal, Anyone, AnyPrincipal, ArnPrincipal, CanonicalUserPrincipal, CompositePrincipal, @@ -444,7 +445,8 @@ describe('IAM policy document', () => { }); }); - test('regional service principals resolve appropriately (with user-set region)', () => { + // Deprecated: 'region' parameter to ServicePrincipal shouldn't be used. + testDeprecated('regional service principals resolve appropriately (with user-set region)', () => { const stack = new Stack(undefined, undefined, { env: { region: 'cn-northeast-1' } }); const s = new PolicyStatement(); s.addActions('test:Action'); From d2f1cfb22cd29c54294b4d2f0c4326d2b96e2e5b Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Mon, 13 Dec 2021 17:43:29 +0100 Subject: [PATCH 15/24] Update snapshot --- .../test/integ.composite-principal.expected.json | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/packages/@aws-cdk/aws-iam/test/integ.composite-principal.expected.json b/packages/@aws-cdk/aws-iam/test/integ.composite-principal.expected.json index a715e411d83ae..b70db09276507 100644 --- a/packages/@aws-cdk/aws-iam/test/integ.composite-principal.expected.json +++ b/packages/@aws-cdk/aws-iam/test/integ.composite-principal.expected.json @@ -9,17 +9,7 @@ "Action": "sts:AssumeRole", "Effect": "Allow", "Principal": { - "Service": { - "Fn::Join": [ - "", - [ - "ec2.", - { - "Ref": "AWS::URLSuffix" - } - ] - ] - }, + "Service": "ec2.amazonaws.com", "AWS": "*" } } From f134fd2867b2832d167c1158c9a754d04dbcf548 Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Tue, 14 Dec 2021 10:38:58 +0100 Subject: [PATCH 16/24] Update snapshot --- .../test/__snapshots__/region-info.test.js.snap | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/packages/@aws-cdk/region-info/test/__snapshots__/region-info.test.js.snap b/packages/@aws-cdk/region-info/test/__snapshots__/region-info.test.js.snap index b90c38e7dbc74..32fdb8a6138fb 100644 --- a/packages/@aws-cdk/region-info/test/__snapshots__/region-info.test.js.snap +++ b/packages/@aws-cdk/region-info/test/__snapshots__/region-info.test.js.snap @@ -253,7 +253,11 @@ Object { "ap-southeast-3": Object { "cdkMetadataResourceAvailable": false, "domainSuffix": "amazonaws.com", + "lambdaInsightsArmVersions": Object { + "1.0.119.0": undefined, + }, "lambdaInsightsVersions": Object { + "1.0.119.0": undefined, "1.0.54.0": undefined, "1.0.86.0": undefined, "1.0.89.0": undefined, @@ -466,7 +470,11 @@ Object { "eu-south-2": Object { "cdkMetadataResourceAvailable": false, "domainSuffix": "amazonaws.com", + "lambdaInsightsArmVersions": Object { + "1.0.119.0": undefined, + }, "lambdaInsightsVersions": Object { + "1.0.119.0": undefined, "1.0.54.0": undefined, "1.0.86.0": undefined, "1.0.89.0": undefined, @@ -803,7 +811,11 @@ Object { "us-iso-west-1": Object { "cdkMetadataResourceAvailable": false, "domainSuffix": "c2s.ic.gov", + "lambdaInsightsArmVersions": Object { + "1.0.119.0": undefined, + }, "lambdaInsightsVersions": Object { + "1.0.119.0": undefined, "1.0.54.0": undefined, "1.0.86.0": undefined, "1.0.89.0": undefined, From efc7f7d6aed333d7260cc5d6f296ffa6c711f7ac Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Tue, 14 Dec 2021 11:01:28 +0100 Subject: [PATCH 17/24] Use 2 partitions instead --- tools/@aws-cdk/cdk-integ-tools/lib/integ-helpers.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tools/@aws-cdk/cdk-integ-tools/lib/integ-helpers.ts b/tools/@aws-cdk/cdk-integ-tools/lib/integ-helpers.ts index 52d330b307110..775ed5202d405 100644 --- a/tools/@aws-cdk/cdk-integ-tools/lib/integ-helpers.ts +++ b/tools/@aws-cdk/cdk-integ-tools/lib/integ-helpers.ts @@ -354,8 +354,11 @@ export const DEFAULT_SYNTH_OPTIONS = { // Enable feature flags for all integ tests ...FUTURE_FLAGS, - // Restrict target partitions to only 'aws', so all service principals stay the same - [TARGET_PARTITIONS]: ['aws'], + // Restricting to these target partitions makes most service principals synthesize to + // `service.${URL_SUFFIX}`, which is technically *incorrect* (it's only `amazonaws.com` + // or `amazonaws.com.cn`, never UrlSuffix for any of the restricted regions) but it's what + // most existing integ tests contain, and we want to disturb as few as possible. + [TARGET_PARTITIONS]: ['aws', 'aws-cn'], }, env: { CDK_INTEG_ACCOUNT: '12345678', From 59f122c3a8215f691e59916aa577eb5d891edda6 Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Tue, 14 Dec 2021 11:36:55 +0100 Subject: [PATCH 18/24] Undo this change --- .../test/integ.composite-principal.expected.json | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/packages/@aws-cdk/aws-iam/test/integ.composite-principal.expected.json b/packages/@aws-cdk/aws-iam/test/integ.composite-principal.expected.json index b70db09276507..a715e411d83ae 100644 --- a/packages/@aws-cdk/aws-iam/test/integ.composite-principal.expected.json +++ b/packages/@aws-cdk/aws-iam/test/integ.composite-principal.expected.json @@ -9,7 +9,17 @@ "Action": "sts:AssumeRole", "Effect": "Allow", "Principal": { - "Service": "ec2.amazonaws.com", + "Service": { + "Fn::Join": [ + "", + [ + "ec2.", + { + "Ref": "AWS::URLSuffix" + } + ] + ] + }, "AWS": "*" } } From 7b1054390b08fbb3e8e5095e4523965604b42c81 Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Tue, 14 Dec 2021 14:03:03 +0100 Subject: [PATCH 19/24] Update lambda-insights tests --- .../aws-lambda/lib/lambda-insights.ts | 16 +- .../aws-lambda/test/lambda-insights.test.ts | 563 ++---------------- packages/@aws-cdk/core/lib/stack.ts | 1 + 3 files changed, 73 insertions(+), 507 deletions(-) diff --git a/packages/@aws-cdk/aws-lambda/lib/lambda-insights.ts b/packages/@aws-cdk/aws-lambda/lib/lambda-insights.ts index da1103b108c22..4d1eee91cf10a 100644 --- a/packages/@aws-cdk/aws-lambda/lib/lambda-insights.ts +++ b/packages/@aws-cdk/aws-lambda/lib/lambda-insights.ts @@ -1,6 +1,6 @@ -import { IResolveContext, Lazy, Stack, Token } from '@aws-cdk/core'; +import { Lazy, Stack, Token } from '@aws-cdk/core'; import { FactName, RegionInfo } from '@aws-cdk/region-info'; -import { Construct } from 'constructs'; +import { Construct, IConstruct } from 'constructs'; import { Architecture } from './architecture'; import { IFunction } from './function-base'; @@ -68,7 +68,7 @@ export abstract class LambdaInsightsVersion { class InsightsVersion extends LambdaInsightsVersion { public readonly layerVersionArn = Lazy.uncachedString({ - produce: (context) => getVersionArn(context, insightsVersion), + produce: (context) => getVersionArn(context.scope, insightsVersion), }); public _bind(_scope: Construct, _function: IFunction): InsightsBindConfig { @@ -80,9 +80,7 @@ export abstract class LambdaInsightsVersion { throw new Error(`Insights version ${insightsVersion} does not exist.`); } return { - arn: Lazy.uncachedString({ - produce: (context) => getVersionArn(context, insightsVersion, arch), - }), + arn: getVersionArn(_scope, insightsVersion, arch), }; } } @@ -108,9 +106,9 @@ export abstract class LambdaInsightsVersion { * * This function is run on CDK synthesis. */ -function getVersionArn(context: IResolveContext, insightsVersion: string, architecture?: string): string { +function getVersionArn(scope: IConstruct, insightsVersion: string, architecture?: string): string { - const scopeStack = Stack.of(context.scope); + const scopeStack = Stack.of(scope); const region = scopeStack.region; const arch = architecture ?? Architecture.X86_64.name; @@ -124,5 +122,5 @@ function getVersionArn(context: IResolveContext, insightsVersion: string, archit } // Otherwise, need to add a mapping to be looked up at deployment time - return scopeStack.regionalFact(FactName.cloudwatchLambdaInsightsVersion(insightsVersion)); + return scopeStack.regionalFact(FactName.cloudwatchLambdaInsightsVersion(insightsVersion, arch)); } diff --git a/packages/@aws-cdk/aws-lambda/test/lambda-insights.test.ts b/packages/@aws-cdk/aws-lambda/test/lambda-insights.test.ts index bfdf095f50870..581106e7a1f92 100644 --- a/packages/@aws-cdk/aws-lambda/test/lambda-insights.test.ts +++ b/packages/@aws-cdk/aws-lambda/test/lambda-insights.test.ts @@ -1,8 +1,9 @@ import '@aws-cdk/assert-internal/jest'; -import { MatchStyle } from '@aws-cdk/assert-internal'; +import { arrayWith, SynthUtils } from '@aws-cdk/assert-internal'; import * as ecr from '@aws-cdk/aws-ecr'; import * as cdk from '@aws-cdk/core'; import * as lambda from '../lib'; +import { Fact, FactName } from '@aws-cdk/region-info'; /** * Boilerplate code to create a Function with a given insights version @@ -14,6 +15,7 @@ function functionWithInsightsVersion( architecture?: lambda.Architecture, ): lambda.IFunction { return new lambda.Function(stack, id, { + functionName: id, code: new lambda.InlineCode('foo'), handler: 'index.handler', runtime: lambda.Runtime.NODEJS_10_X, @@ -77,10 +79,9 @@ describe('lambda-insights', () => { }); // AF-SOUTH-1 exists, 1.0.54.0 exists, but 1.0.54.0 isn't supported in AF-SOUTH-1 - functionWithInsightsVersion(stack, 'BadVersion', lambda.LambdaInsightsVersion.VERSION_1_0_54_0); - - // On synthesis it should throw an error - expect(() => app.synth()).toThrow('Insights version 1.0.54.0 is not supported in region af-south-1'); + expect(() => { + functionWithInsightsVersion(stack, 'BadVersion', lambda.LambdaInsightsVersion.VERSION_1_0_54_0); + }).toThrow('Insights version 1.0.54.0 is not supported in region af-south-1'); }); test('using a specific version without providing a region', () => { @@ -97,7 +98,7 @@ describe('lambda-insights', () => { { Ref: 'AWS::Region', }, - '1_0_98_0', + '1_0_98_0_x86_64', ], }], }); @@ -114,220 +115,25 @@ describe('lambda-insights', () => { functionWithInsightsVersion(stack, 'MyLambda1', lambda.LambdaInsightsVersion.VERSION_1_0_98_0); functionWithInsightsVersion(stack, 'MyLambda2', lambda.LambdaInsightsVersion.VERSION_1_0_98_0); - /* eslint-disable quote-props */ - expect(stack).toMatchTemplate( - { - Resources: { - MyLambda1ServiceRole69A7E1EA: { - Type: 'AWS::IAM::Role', - Properties: { - AssumeRolePolicyDocument: { - Statement: [ - { - Action: 'sts:AssumeRole', - Effect: 'Allow', - Principal: { - Service: 'lambda.amazonaws.com', - }, - }, - ], - Version: '2012-10-17', - }, - ManagedPolicyArns: [ - { - 'Fn::Join': [ - '', - [ - 'arn:', - { - Ref: 'AWS::Partition', - }, - ':iam::aws:policy/service-role/AWSLambdaBasicExecutionRole', - ], - ], - }, - { - 'Fn::Join': [ - '', - [ - 'arn:', - { - Ref: 'AWS::Partition', - }, - ':iam::aws:policy/CloudWatchLambdaInsightsExecutionRolePolicy', - ], - ], - }, - ], - }, - }, - MyLambda1AAFB4554: { - Type: 'AWS::Lambda::Function', - Properties: { - Code: { - ZipFile: 'foo', - }, - Role: { - 'Fn::GetAtt': ['MyLambda1ServiceRole69A7E1EA', 'Arn'], - }, - Handler: 'index.handler', - Layers: [ - { - 'Fn::FindInMap': [ - 'CloudwatchlambdainsightsversionMap', - { - Ref: 'AWS::Region', - }, - '1_0_98_0', - ], - }, - ], - Runtime: 'nodejs10.x', - }, - DependsOn: ['MyLambda1ServiceRole69A7E1EA'], - }, - MyLambda2ServiceRoleD09B370C: { - Type: 'AWS::IAM::Role', - Properties: { - AssumeRolePolicyDocument: { - Statement: [ - { - Action: 'sts:AssumeRole', - Effect: 'Allow', - Principal: { - Service: 'lambda.amazonaws.com', - }, - }, - ], - Version: '2012-10-17', - }, - ManagedPolicyArns: [ - { - 'Fn::Join': [ - '', - [ - 'arn:', - { - Ref: 'AWS::Partition', - }, - ':iam::aws:policy/service-role/AWSLambdaBasicExecutionRole', - ], - ], - }, - { - 'Fn::Join': [ - '', - [ - 'arn:', - { - Ref: 'AWS::Partition', - }, - ':iam::aws:policy/CloudWatchLambdaInsightsExecutionRolePolicy', - ], - ], - }, - ], - }, - }, - MyLambda2254B54D5: { - Type: 'AWS::Lambda::Function', - Properties: { - Code: { - ZipFile: 'foo', - }, - Role: { - 'Fn::GetAtt': ['MyLambda2ServiceRoleD09B370C', 'Arn'], - }, - Handler: 'index.handler', - Layers: [ - { - 'Fn::FindInMap': [ - 'CloudwatchlambdainsightsversionMap', - { - Ref: 'AWS::Region', - }, - '1_0_98_0', - ], - }, - ], - Runtime: 'nodejs10.x', - }, - DependsOn: ['MyLambda2ServiceRoleD09B370C'], - }, - }, - Mappings: { - CloudwatchlambdainsightsversionMap: { - 'af-south-1': { - '1_0_98_0': 'arn:aws:lambda:af-south-1:012438385374:layer:LambdaInsightsExtension:8', - }, - 'ap-east-1': { - '1_0_98_0': 'arn:aws:lambda:ap-east-1:519774774795:layer:LambdaInsightsExtension:8', - }, - 'ap-northeast-1': { - '1_0_98_0': 'arn:aws:lambda:ap-northeast-1:580247275435:layer:LambdaInsightsExtension:14', - }, - 'ap-northeast-2': { - '1_0_98_0': 'arn:aws:lambda:ap-northeast-2:580247275435:layer:LambdaInsightsExtension:14', - }, - 'ap-south-1': { - '1_0_98_0': 'arn:aws:lambda:ap-south-1:580247275435:layer:LambdaInsightsExtension:14', - }, - 'ap-southeast-1': { - '1_0_98_0': 'arn:aws:lambda:ap-southeast-1:580247275435:layer:LambdaInsightsExtension:14', - }, - 'ap-southeast-2': { - '1_0_98_0': 'arn:aws:lambda:ap-southeast-2:580247275435:layer:LambdaInsightsExtension:14', - }, - 'ca-central-1': { - '1_0_98_0': 'arn:aws:lambda:ca-central-1:580247275435:layer:LambdaInsightsExtension:14', - }, - 'cn-north-1': { - '1_0_98_0': 'arn:aws-cn:lambda:cn-north-1:488211338238:layer:LambdaInsightsExtension:8', - }, - 'cn-northwest-1': { - '1_0_98_0': 'arn:aws-cn:lambda:cn-northwest-1:488211338238:layer:LambdaInsightsExtension:8', - }, - 'eu-central-1': { - '1_0_98_0': 'arn:aws:lambda:eu-central-1:580247275435:layer:LambdaInsightsExtension:14', - }, - 'eu-north-1': { - '1_0_98_0': 'arn:aws:lambda:eu-north-1:580247275435:layer:LambdaInsightsExtension:14', - }, - 'eu-south-1': { - '1_0_98_0': 'arn:aws:lambda:eu-south-1:339249233099:layer:LambdaInsightsExtension:8', - }, - 'eu-west-1': { - '1_0_98_0': 'arn:aws:lambda:eu-west-1:580247275435:layer:LambdaInsightsExtension:14', - }, - 'eu-west-2': { - '1_0_98_0': 'arn:aws:lambda:eu-west-2:580247275435:layer:LambdaInsightsExtension:14', - }, - 'eu-west-3': { - '1_0_98_0': 'arn:aws:lambda:eu-west-3:580247275435:layer:LambdaInsightsExtension:14', - }, - 'me-south-1': { - '1_0_98_0': 'arn:aws:lambda:me-south-1:285320876703:layer:LambdaInsightsExtension:8', - }, - 'sa-east-1': { - '1_0_98_0': 'arn:aws:lambda:sa-east-1:580247275435:layer:LambdaInsightsExtension:14', - }, - 'us-east-1': { - '1_0_98_0': 'arn:aws:lambda:us-east-1:580247275435:layer:LambdaInsightsExtension:14', - }, - 'us-east-2': { - '1_0_98_0': 'arn:aws:lambda:us-east-2:580247275435:layer:LambdaInsightsExtension:14', - }, - 'us-west-1': { - '1_0_98_0': 'arn:aws:lambda:us-west-1:580247275435:layer:LambdaInsightsExtension:14', - }, - 'us-west-2': { - '1_0_98_0': 'arn:aws:lambda:us-west-2:580247275435:layer:LambdaInsightsExtension:14', - }, - }, - }, - }, - MatchStyle.EXACT, - ); + expect(stack).toHaveResource('AWS::Lambda::Function', { + FunctionName: 'MyLambda1', + Layers: [{ + 'Fn::FindInMap': ['CloudwatchlambdainsightsversionMap', { Ref: 'AWS::Region' }, '1_0_98_0_x86_64'], + }], + }); + + expect(stack).toHaveResource('AWS::Lambda::Function', { + FunctionName: 'MyLambda2', + Layers: [{ + 'Fn::FindInMap': ['CloudwatchlambdainsightsversionMap', { Ref: 'AWS::Region' }, '1_0_98_0_x86_64'], + }], + }); + + const template = SynthUtils.toCloudFormation(stack); + expect(template.Mappings.CloudwatchlambdainsightsversionMap?.['af-south-1']).toEqual({ + '1_0_98_0_x86_64': 'arn:aws:lambda:af-south-1:012438385374:layer:LambdaInsightsExtension:8', + }); + // On synthesis it should not throw an error expect(() => app.synth()).not.toThrow(); }); @@ -343,31 +149,23 @@ describe('lambda-insights', () => { expect(stack).toCountResources('AWS::Lambda::LayerVersion', 0); expect(stack).toHaveResourceLike('AWS::IAM::Role', { - 'AssumeRolePolicyDocument': { - 'Statement': [ + AssumeRolePolicyDocument: { + Statement: [ { - 'Action': 'sts:AssumeRole', - 'Principal': { - 'Service': 'lambda.amazonaws.com', - }, + Action: 'sts:AssumeRole', + Principal: { Service: 'lambda.amazonaws.com' }, }, ], }, - 'ManagedPolicyArns': [ - {}, + ManagedPolicyArns: arrayWith( { - 'Fn::Join': [ - '', - [ - 'arn:', - { - 'Ref': 'AWS::Partition', - }, - ':iam::aws:policy/CloudWatchLambdaInsightsExecutionRolePolicy', - ], - ], + 'Fn::Join': ['', [ + 'arn:', + { Ref: 'AWS::Partition' }, + ':iam::aws:policy/CloudWatchLambdaInsightsExecutionRolePolicy', + ]], }, - ], + ), }); }); @@ -398,275 +196,44 @@ describe('lambda-insights', () => { const stack = new cdk.Stack(app, 'Stack', { env: { account: '123456789012', region: 'us-west-1' }, }); - functionWithInsightsVersion(stack, 'MyLambda', lambda.LambdaInsightsVersion.VERSION_1_0_119_0, lambda.Architecture.ARM_64); - // On synthesis it should not throw an error - expect(() => app.synth()).toThrow('Insights version 1.0.119.0 is not supported in region us-west-1'); + expect(() => { + functionWithInsightsVersion(stack, 'MyLambda', lambda.LambdaInsightsVersion.VERSION_1_0_119_0, lambda.Architecture.ARM_64); + }).toThrow('Insights version 1.0.119.0 is not supported in region us-west-1'); }); test('can create two functions, with different architectures in a region agnostic stack with the same version', () => { + // We mess with the fact database a bit here -- add a fact for the ARM LambdaInsights layer which + // is different from the existing facts, to force the region info to render a lookup table (instead + // of being able to just insert a literal). + Fact.register({ name: FactName.cloudwatchLambdaInsightsVersion('1.0.119.0', 'arm64'), region: 'eu-west-1', value: 'CompletelyDifferent' }, true); + const app = new cdk.App(); const stack = new cdk.Stack(app, 'Stack', {}); functionWithInsightsVersion(stack, 'MyLambda1', lambda.LambdaInsightsVersion.VERSION_1_0_119_0); functionWithInsightsVersion(stack, 'MyLambda2', lambda.LambdaInsightsVersion.VERSION_1_0_119_0, lambda.Architecture.ARM_64); - /* eslint-disable quote-props */ - expect(stack).toMatchTemplate({ - Resources: { - MyLambda1ServiceRole69A7E1EA: { - 'Type': 'AWS::IAM::Role', - 'Properties': { - 'AssumeRolePolicyDocument': { - 'Statement': [ - { - 'Action': 'sts:AssumeRole', - 'Effect': 'Allow', - 'Principal': { - 'Service': 'lambda.amazonaws.com', - }, - }, - ], - 'Version': '2012-10-17', - }, - 'ManagedPolicyArns': [ - { - 'Fn::Join': [ - '', - [ - 'arn:', - { - 'Ref': 'AWS::Partition', - }, - ':iam::aws:policy/service-role/AWSLambdaBasicExecutionRole', - ], - ], - }, - { - 'Fn::Join': [ - '', - [ - 'arn:', - { - 'Ref': 'AWS::Partition', - }, - ':iam::aws:policy/CloudWatchLambdaInsightsExecutionRolePolicy', - ], - ], - }, - ], - }, - }, - MyLambda1AAFB4554: { - 'Type': 'AWS::Lambda::Function', - 'Properties': { - 'Code': { - 'ZipFile': 'foo', - }, - 'Role': { - 'Fn::GetAtt': [ - 'MyLambda1ServiceRole69A7E1EA', - 'Arn', - ], - }, - 'Handler': 'index.handler', - 'Layers': [ - { - 'Fn::FindInMap': [ - 'LambdaInsightsVersions101190', - { - 'Ref': 'AWS::Region', - }, - 'arn', - ], - }, - ], - 'Runtime': 'nodejs10.x', - }, - 'DependsOn': [ - 'MyLambda1ServiceRole69A7E1EA', - ], - }, - MyLambda2ServiceRoleD09B370C: { - 'Type': 'AWS::IAM::Role', - 'Properties': { - 'AssumeRolePolicyDocument': { - 'Statement': [ - { - 'Action': 'sts:AssumeRole', - 'Effect': 'Allow', - 'Principal': { - 'Service': 'lambda.amazonaws.com', - }, - }, - ], - 'Version': '2012-10-17', - }, - 'ManagedPolicyArns': [ - { - 'Fn::Join': [ - '', - [ - 'arn:', - { - 'Ref': 'AWS::Partition', - }, - ':iam::aws:policy/service-role/AWSLambdaBasicExecutionRole', - ], - ], - }, - { - 'Fn::Join': [ - '', - [ - 'arn:', - { - 'Ref': 'AWS::Partition', - }, - ':iam::aws:policy/CloudWatchLambdaInsightsExecutionRolePolicy', - ], - ], - }, - ], - }, - }, - MyLambda2254B54D5: { - 'Type': 'AWS::Lambda::Function', - 'Properties': { - 'Code': { - 'ZipFile': 'foo', - }, - 'Role': { - 'Fn::GetAtt': [ - 'MyLambda2ServiceRoleD09B370C', - 'Arn', - ], - }, - 'Architectures': [ - 'arm64', - ], - 'Handler': 'index.handler', - 'Layers': [ - { - 'Fn::FindInMap': [ - 'LambdaInsightsVersions101190arm64', - { - 'Ref': 'AWS::Region', - }, - 'arn', - ], - }, - ], - 'Runtime': 'nodejs10.x', - }, - 'DependsOn': [ - 'MyLambda2ServiceRoleD09B370C', - ], - }, - }, - Mappings: { - LambdaInsightsVersions101190: { - 'af-south-1': { - 'arn': 'arn:aws:lambda:af-south-1:012438385374:layer:LambdaInsightsExtension:9', - }, - 'ap-east-1': { - 'arn': 'arn:aws:lambda:ap-east-1:519774774795:layer:LambdaInsightsExtension:9', - }, - 'ap-northeast-1': { - 'arn': 'arn:aws:lambda:ap-northeast-1:580247275435:layer:LambdaInsightsExtension:23', - }, - 'ap-northeast-2': { - 'arn': 'arn:aws:lambda:ap-northeast-2:580247275435:layer:LambdaInsightsExtension:16', - }, - 'ap-south-1': { - 'arn': 'arn:aws:lambda:ap-south-1:580247275435:layer:LambdaInsightsExtension:16', - }, - 'ap-southeast-1': { - 'arn': 'arn:aws:lambda:ap-southeast-1:580247275435:layer:LambdaInsightsExtension:16', - }, - 'ap-southeast-2': { - 'arn': 'arn:aws:lambda:ap-southeast-2:580247275435:layer:LambdaInsightsExtension:16', - }, - 'ca-central-1': { - 'arn': 'arn:aws:lambda:ca-central-1:580247275435:layer:LambdaInsightsExtension:16', - }, - 'cn-north-1': { - 'arn': 'arn:aws-cn:lambda:cn-north-1:488211338238:layer:LambdaInsightsExtension:9', - }, - 'cn-northwest-1': { - 'arn': 'arn:aws-cn:lambda:cn-northwest-1:488211338238:layer:LambdaInsightsExtension:9', - }, - 'eu-central-1': { - 'arn': 'arn:aws:lambda:eu-central-1:580247275435:layer:LambdaInsightsExtension:16', - }, - 'eu-north-1': { - 'arn': 'arn:aws:lambda:eu-north-1:580247275435:layer:LambdaInsightsExtension:16', - }, - 'eu-south-1': { - 'arn': 'arn:aws:lambda:eu-south-1:339249233099:layer:LambdaInsightsExtension:9', - }, - 'eu-west-1': { - 'arn': 'arn:aws:lambda:eu-west-1:580247275435:layer:LambdaInsightsExtension:16', - }, - 'eu-west-2': { - 'arn': 'arn:aws:lambda:eu-west-2:580247275435:layer:LambdaInsightsExtension:16', - }, - 'eu-west-3': { - 'arn': 'arn:aws:lambda:eu-west-3:580247275435:layer:LambdaInsightsExtension:16', - }, - 'me-south-1': { - 'arn': 'arn:aws:lambda:me-south-1:285320876703:layer:LambdaInsightsExtension:9', - }, - 'sa-east-1': { - 'arn': 'arn:aws:lambda:sa-east-1:580247275435:layer:LambdaInsightsExtension:16', - }, - 'us-east-1': { - 'arn': 'arn:aws:lambda:us-east-1:580247275435:layer:LambdaInsightsExtension:16', - }, - 'us-east-2': { - 'arn': 'arn:aws:lambda:us-east-2:580247275435:layer:LambdaInsightsExtension:16', - }, - 'us-west-1': { - 'arn': 'arn:aws:lambda:us-west-1:580247275435:layer:LambdaInsightsExtension:16', - }, - 'us-west-2': { - 'arn': 'arn:aws:lambda:us-west-2:580247275435:layer:LambdaInsightsExtension:16', - }, - }, - 'LambdaInsightsVersions101190arm64': { - 'ap-northeast-1': { - 'arn': 'arn:aws:lambda:ap-northeast-1:580247275435:layer:LambdaInsightsExtension-Arm64:1', - }, - 'ap-south-1': { - 'arn': 'arn:aws:lambda:ap-south-1:580247275435:layer:LambdaInsightsExtension-Arm64:1', - }, - 'ap-southeast-1': { - 'arn': 'arn:aws:lambda:ap-southeast-1:580247275435:layer:LambdaInsightsExtension-Arm64:1', - }, - 'ap-southeast-2': { - 'arn': 'arn:aws:lambda:ap-southeast-2:580247275435:layer:LambdaInsightsExtension-Arm64:1', - }, - 'eu-central-1': { - 'arn': 'arn:aws:lambda:eu-central-1:580247275435:layer:LambdaInsightsExtension-Arm64:1', - }, - 'eu-west-1': { - 'arn': 'arn:aws:lambda:eu-west-1:580247275435:layer:LambdaInsightsExtension-Arm64:1', - }, - 'eu-west-2': { - 'arn': 'arn:aws:lambda:eu-west-2:580247275435:layer:LambdaInsightsExtension-Arm64:1', - }, - 'us-east-1': { - 'arn': 'arn:aws:lambda:us-east-1:580247275435:layer:LambdaInsightsExtension-Arm64:1', - }, - 'us-east-2': { - 'arn': 'arn:aws:lambda:us-east-2:580247275435:layer:LambdaInsightsExtension-Arm64:1', - }, - 'us-west-2': { - 'arn': 'arn:aws:lambda:us-west-2:580247275435:layer:LambdaInsightsExtension-Arm64:1', - }, - }, - }, - }, MatchStyle.EXACT); + expect(stack).toHaveResource('AWS::Lambda::Function', { + FunctionName: 'MyLambda1', + Layers: [{ + 'Fn::FindInMap': ['CloudwatchlambdainsightsversionMap', { Ref: 'AWS::Region' }, '1_0_119_0_x86_64'], + }], + }); + + expect(stack).toHaveResource('AWS::Lambda::Function', { + FunctionName: 'MyLambda2', + Layers: [{ + 'Fn::FindInMap': ['CloudwatchlambdainsightsversionMap', { Ref: 'AWS::Region' }, '1_0_119_0_arm64'], + }], + }); + + const template = SynthUtils.toCloudFormation(stack); + expect(template.Mappings.CloudwatchlambdainsightsversionMap?.['ap-south-1']).toEqual({ + '1_0_119_0_x86_64': 'arn:aws:lambda:ap-south-1:580247275435:layer:LambdaInsightsExtension:16', + '1_0_119_0_arm64': 'arn:aws:lambda:ap-south-1:580247275435:layer:LambdaInsightsExtension-Arm64:1', + }); + // On synthesis it should not throw an error expect(() => app.synth()).not.toThrow(); }); diff --git a/packages/@aws-cdk/core/lib/stack.ts b/packages/@aws-cdk/core/lib/stack.ts index 6117a9a19e972..0efd45fc14b3f 100644 --- a/packages/@aws-cdk/core/lib/stack.ts +++ b/packages/@aws-cdk/core/lib/stack.ts @@ -1354,3 +1354,4 @@ import { Token, Tokenization } from './token'; import { referenceNestedStackValueInParent } from './private/refs'; import { Fact, RegionInfo } from '@aws-cdk/region-info'; import { deployTimeLookup } from './private/region-lookup'; + From 9a6be585d89e2bda508afab6fbd2a5270a8a7b69 Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Tue, 14 Dec 2021 14:17:16 +0100 Subject: [PATCH 20/24] Forgot snapshot --- ...nteg.lambda-insights-mapping.expected.json | 181 ++++++------------ 1 file changed, 56 insertions(+), 125 deletions(-) diff --git a/packages/@aws-cdk/aws-lambda/test/integ.lambda-insights-mapping.expected.json b/packages/@aws-cdk/aws-lambda/test/integ.lambda-insights-mapping.expected.json index ee644d2e02678..a7a94e5d13ba7 100644 --- a/packages/@aws-cdk/aws-lambda/test/integ.lambda-insights-mapping.expected.json +++ b/packages/@aws-cdk/aws-lambda/test/integ.lambda-insights-mapping.expected.json @@ -291,7 +291,7 @@ { "Ref": "AWS::Region" }, - "1_0_98_0" + "1_0_98_0_x86_64" ] } ], @@ -360,11 +360,11 @@ "Layers": [ { "Fn::FindInMap": [ - "LambdaInsightsVersions101190", + "CloudwatchlambdainsightsversionMap", { "Ref": "AWS::Region" }, - "arn" + "1_0_119_0_x86_64" ] } ], @@ -435,12 +435,15 @@ "Handler": "index.handler", "Layers": [ { - "Fn::FindInMap": [ - "LambdaInsightsVersions101190arm64", - { - "Ref": "AWS::Region" - }, - "arn" + "Fn::Join": [ + "", + [ + "arn:aws:lambda:", + { + "Ref": "AWS::Region" + }, + ":580247275435:layer:LambdaInsightsExtension-Arm64:1" + ] ] } ], @@ -454,164 +457,92 @@ "Mappings": { "CloudwatchlambdainsightsversionMap": { "af-south-1": { - "1_0_98_0": "arn:aws:lambda:af-south-1:012438385374:layer:LambdaInsightsExtension:8" + "1_0_98_0_x86_64": "arn:aws:lambda:af-south-1:012438385374:layer:LambdaInsightsExtension:8", + "1_0_119_0_x86_64": "arn:aws:lambda:af-south-1:012438385374:layer:LambdaInsightsExtension:9" }, "ap-east-1": { - "1_0_98_0": "arn:aws:lambda:ap-east-1:519774774795:layer:LambdaInsightsExtension:8" + "1_0_98_0_x86_64": "arn:aws:lambda:ap-east-1:519774774795:layer:LambdaInsightsExtension:8", + "1_0_119_0_x86_64": "arn:aws:lambda:ap-east-1:519774774795:layer:LambdaInsightsExtension:9" }, "ap-northeast-1": { - "1_0_98_0": "arn:aws:lambda:ap-northeast-1:580247275435:layer:LambdaInsightsExtension:14" + "1_0_98_0_x86_64": "arn:aws:lambda:ap-northeast-1:580247275435:layer:LambdaInsightsExtension:14", + "1_0_119_0_x86_64": "arn:aws:lambda:ap-northeast-1:580247275435:layer:LambdaInsightsExtension:23" }, "ap-northeast-2": { - "1_0_98_0": "arn:aws:lambda:ap-northeast-2:580247275435:layer:LambdaInsightsExtension:14" + "1_0_98_0_x86_64": "arn:aws:lambda:ap-northeast-2:580247275435:layer:LambdaInsightsExtension:14", + "1_0_119_0_x86_64": "arn:aws:lambda:ap-northeast-2:580247275435:layer:LambdaInsightsExtension:16" }, "ap-south-1": { - "1_0_98_0": "arn:aws:lambda:ap-south-1:580247275435:layer:LambdaInsightsExtension:14" + "1_0_98_0_x86_64": "arn:aws:lambda:ap-south-1:580247275435:layer:LambdaInsightsExtension:14", + "1_0_119_0_x86_64": "arn:aws:lambda:ap-south-1:580247275435:layer:LambdaInsightsExtension:16" }, "ap-southeast-1": { - "1_0_98_0": "arn:aws:lambda:ap-southeast-1:580247275435:layer:LambdaInsightsExtension:14" + "1_0_98_0_x86_64": "arn:aws:lambda:ap-southeast-1:580247275435:layer:LambdaInsightsExtension:14", + "1_0_119_0_x86_64": "arn:aws:lambda:ap-southeast-1:580247275435:layer:LambdaInsightsExtension:16" }, "ap-southeast-2": { - "1_0_98_0": "arn:aws:lambda:ap-southeast-2:580247275435:layer:LambdaInsightsExtension:14" + "1_0_98_0_x86_64": "arn:aws:lambda:ap-southeast-2:580247275435:layer:LambdaInsightsExtension:14", + "1_0_119_0_x86_64": "arn:aws:lambda:ap-southeast-2:580247275435:layer:LambdaInsightsExtension:16" }, "ca-central-1": { - "1_0_98_0": "arn:aws:lambda:ca-central-1:580247275435:layer:LambdaInsightsExtension:14" - }, - "eu-central-1": { - "1_0_98_0": "arn:aws:lambda:eu-central-1:580247275435:layer:LambdaInsightsExtension:14" - }, - "eu-north-1": { - "1_0_98_0": "arn:aws:lambda:eu-north-1:580247275435:layer:LambdaInsightsExtension:14" - }, - "eu-south-1": { - "1_0_98_0": "arn:aws:lambda:eu-south-1:339249233099:layer:LambdaInsightsExtension:8" - }, - "eu-west-1": { - "1_0_98_0": "arn:aws:lambda:eu-west-1:580247275435:layer:LambdaInsightsExtension:14" - }, - "eu-west-2": { - "1_0_98_0": "arn:aws:lambda:eu-west-2:580247275435:layer:LambdaInsightsExtension:14" - }, - "eu-west-3": { - "1_0_98_0": "arn:aws:lambda:eu-west-3:580247275435:layer:LambdaInsightsExtension:14" - }, - "me-south-1": { - "1_0_98_0": "arn:aws:lambda:me-south-1:285320876703:layer:LambdaInsightsExtension:8" - }, - "sa-east-1": { - "1_0_98_0": "arn:aws:lambda:sa-east-1:580247275435:layer:LambdaInsightsExtension:14" - }, - "us-east-1": { - "1_0_98_0": "arn:aws:lambda:us-east-1:580247275435:layer:LambdaInsightsExtension:14" - }, - "us-east-2": { - "1_0_98_0": "arn:aws:lambda:us-east-2:580247275435:layer:LambdaInsightsExtension:14" - }, - "us-west-1": { - "1_0_98_0": "arn:aws:lambda:us-west-1:580247275435:layer:LambdaInsightsExtension:14" - }, - "us-west-2": { - "1_0_98_0": "arn:aws:lambda:us-west-2:580247275435:layer:LambdaInsightsExtension:14" - } - }, - "LambdaInsightsVersions101190": { - "af-south-1": { - "arn": "arn:aws:lambda:af-south-1:012438385374:layer:LambdaInsightsExtension:9" - }, - "ap-east-1": { - "arn": "arn:aws:lambda:ap-east-1:519774774795:layer:LambdaInsightsExtension:9" - }, - "ap-northeast-1": { - "arn": "arn:aws:lambda:ap-northeast-1:580247275435:layer:LambdaInsightsExtension:23" - }, - "ap-northeast-2": { - "arn": "arn:aws:lambda:ap-northeast-2:580247275435:layer:LambdaInsightsExtension:16" - }, - "ap-south-1": { - "arn": "arn:aws:lambda:ap-south-1:580247275435:layer:LambdaInsightsExtension:16" - }, - "ap-southeast-1": { - "arn": "arn:aws:lambda:ap-southeast-1:580247275435:layer:LambdaInsightsExtension:16" - }, - "ap-southeast-2": { - "arn": "arn:aws:lambda:ap-southeast-2:580247275435:layer:LambdaInsightsExtension:16" - }, - "ca-central-1": { - "arn": "arn:aws:lambda:ca-central-1:580247275435:layer:LambdaInsightsExtension:16" + "1_0_98_0_x86_64": "arn:aws:lambda:ca-central-1:580247275435:layer:LambdaInsightsExtension:14", + "1_0_119_0_x86_64": "arn:aws:lambda:ca-central-1:580247275435:layer:LambdaInsightsExtension:16" }, "cn-north-1": { - "arn": "arn:aws-cn:lambda:cn-north-1:488211338238:layer:LambdaInsightsExtension:9" + "1_0_98_0_x86_64": "arn:aws-cn:lambda:cn-north-1:488211338238:layer:LambdaInsightsExtension:8", + "1_0_119_0_x86_64": "arn:aws-cn:lambda:cn-north-1:488211338238:layer:LambdaInsightsExtension:9" }, "cn-northwest-1": { - "arn": "arn:aws-cn:lambda:cn-northwest-1:488211338238:layer:LambdaInsightsExtension:9" + "1_0_98_0_x86_64": "arn:aws-cn:lambda:cn-northwest-1:488211338238:layer:LambdaInsightsExtension:8", + "1_0_119_0_x86_64": "arn:aws-cn:lambda:cn-northwest-1:488211338238:layer:LambdaInsightsExtension:9" }, "eu-central-1": { - "arn": "arn:aws:lambda:eu-central-1:580247275435:layer:LambdaInsightsExtension:16" + "1_0_98_0_x86_64": "arn:aws:lambda:eu-central-1:580247275435:layer:LambdaInsightsExtension:14", + "1_0_119_0_x86_64": "arn:aws:lambda:eu-central-1:580247275435:layer:LambdaInsightsExtension:16" }, "eu-north-1": { - "arn": "arn:aws:lambda:eu-north-1:580247275435:layer:LambdaInsightsExtension:16" + "1_0_98_0_x86_64": "arn:aws:lambda:eu-north-1:580247275435:layer:LambdaInsightsExtension:14", + "1_0_119_0_x86_64": "arn:aws:lambda:eu-north-1:580247275435:layer:LambdaInsightsExtension:16" }, "eu-south-1": { - "arn": "arn:aws:lambda:eu-south-1:339249233099:layer:LambdaInsightsExtension:9" + "1_0_98_0_x86_64": "arn:aws:lambda:eu-south-1:339249233099:layer:LambdaInsightsExtension:8", + "1_0_119_0_x86_64": "arn:aws:lambda:eu-south-1:339249233099:layer:LambdaInsightsExtension:9" }, "eu-west-1": { - "arn": "arn:aws:lambda:eu-west-1:580247275435:layer:LambdaInsightsExtension:16" + "1_0_98_0_x86_64": "arn:aws:lambda:eu-west-1:580247275435:layer:LambdaInsightsExtension:14", + "1_0_119_0_x86_64": "arn:aws:lambda:eu-west-1:580247275435:layer:LambdaInsightsExtension:16" }, "eu-west-2": { - "arn": "arn:aws:lambda:eu-west-2:580247275435:layer:LambdaInsightsExtension:16" + "1_0_98_0_x86_64": "arn:aws:lambda:eu-west-2:580247275435:layer:LambdaInsightsExtension:14", + "1_0_119_0_x86_64": "arn:aws:lambda:eu-west-2:580247275435:layer:LambdaInsightsExtension:16" }, "eu-west-3": { - "arn": "arn:aws:lambda:eu-west-3:580247275435:layer:LambdaInsightsExtension:16" + "1_0_98_0_x86_64": "arn:aws:lambda:eu-west-3:580247275435:layer:LambdaInsightsExtension:14", + "1_0_119_0_x86_64": "arn:aws:lambda:eu-west-3:580247275435:layer:LambdaInsightsExtension:16" }, "me-south-1": { - "arn": "arn:aws:lambda:me-south-1:285320876703:layer:LambdaInsightsExtension:9" + "1_0_98_0_x86_64": "arn:aws:lambda:me-south-1:285320876703:layer:LambdaInsightsExtension:8", + "1_0_119_0_x86_64": "arn:aws:lambda:me-south-1:285320876703:layer:LambdaInsightsExtension:9" }, "sa-east-1": { - "arn": "arn:aws:lambda:sa-east-1:580247275435:layer:LambdaInsightsExtension:16" + "1_0_98_0_x86_64": "arn:aws:lambda:sa-east-1:580247275435:layer:LambdaInsightsExtension:14", + "1_0_119_0_x86_64": "arn:aws:lambda:sa-east-1:580247275435:layer:LambdaInsightsExtension:16" }, "us-east-1": { - "arn": "arn:aws:lambda:us-east-1:580247275435:layer:LambdaInsightsExtension:16" + "1_0_98_0_x86_64": "arn:aws:lambda:us-east-1:580247275435:layer:LambdaInsightsExtension:14", + "1_0_119_0_x86_64": "arn:aws:lambda:us-east-1:580247275435:layer:LambdaInsightsExtension:16" }, "us-east-2": { - "arn": "arn:aws:lambda:us-east-2:580247275435:layer:LambdaInsightsExtension:16" + "1_0_98_0_x86_64": "arn:aws:lambda:us-east-2:580247275435:layer:LambdaInsightsExtension:14", + "1_0_119_0_x86_64": "arn:aws:lambda:us-east-2:580247275435:layer:LambdaInsightsExtension:16" }, "us-west-1": { - "arn": "arn:aws:lambda:us-west-1:580247275435:layer:LambdaInsightsExtension:16" - }, - "us-west-2": { - "arn": "arn:aws:lambda:us-west-2:580247275435:layer:LambdaInsightsExtension:16" - } - }, - "LambdaInsightsVersions101190arm64": { - "ap-northeast-1": { - "arn": "arn:aws:lambda:ap-northeast-1:580247275435:layer:LambdaInsightsExtension-Arm64:1" - }, - "ap-south-1": { - "arn": "arn:aws:lambda:ap-south-1:580247275435:layer:LambdaInsightsExtension-Arm64:1" - }, - "ap-southeast-1": { - "arn": "arn:aws:lambda:ap-southeast-1:580247275435:layer:LambdaInsightsExtension-Arm64:1" - }, - "ap-southeast-2": { - "arn": "arn:aws:lambda:ap-southeast-2:580247275435:layer:LambdaInsightsExtension-Arm64:1" - }, - "eu-central-1": { - "arn": "arn:aws:lambda:eu-central-1:580247275435:layer:LambdaInsightsExtension-Arm64:1" - }, - "eu-west-1": { - "arn": "arn:aws:lambda:eu-west-1:580247275435:layer:LambdaInsightsExtension-Arm64:1" - }, - "eu-west-2": { - "arn": "arn:aws:lambda:eu-west-2:580247275435:layer:LambdaInsightsExtension-Arm64:1" - }, - "us-east-1": { - "arn": "arn:aws:lambda:us-east-1:580247275435:layer:LambdaInsightsExtension-Arm64:1" - }, - "us-east-2": { - "arn": "arn:aws:lambda:us-east-2:580247275435:layer:LambdaInsightsExtension-Arm64:1" + "1_0_98_0_x86_64": "arn:aws:lambda:us-west-1:580247275435:layer:LambdaInsightsExtension:14", + "1_0_119_0_x86_64": "arn:aws:lambda:us-west-1:580247275435:layer:LambdaInsightsExtension:16" }, "us-west-2": { - "arn": "arn:aws:lambda:us-west-2:580247275435:layer:LambdaInsightsExtension-Arm64:1" + "1_0_98_0_x86_64": "arn:aws:lambda:us-west-2:580247275435:layer:LambdaInsightsExtension:14", + "1_0_119_0_x86_64": "arn:aws:lambda:us-west-2:580247275435:layer:LambdaInsightsExtension:16" } } } From 7927e4971e2236b42924db04f2268b2a3ffc262f Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Tue, 14 Dec 2021 14:39:39 +0100 Subject: [PATCH 21/24] Fix CodeBuild --- .../@aws-cdk/aws-codebuild/lib/linux-gpu-build-image.ts | 4 ++-- ...eg.aws-deep-learning-container-build-image.expected.json | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/@aws-cdk/aws-codebuild/lib/linux-gpu-build-image.ts b/packages/@aws-cdk/aws-codebuild/lib/linux-gpu-build-image.ts index 921fe672c9bfa..f1b9dd4f3158f 100644 --- a/packages/@aws-cdk/aws-codebuild/lib/linux-gpu-build-image.ts +++ b/packages/@aws-cdk/aws-codebuild/lib/linux-gpu-build-image.ts @@ -10,7 +10,7 @@ import { // keep this import separate from other imports to reduce chance for merge conflicts with v2-main // eslint-disable-next-line no-duplicate-imports, import/order -import { Construct, Lazy } from '@aws-cdk/core'; +import { Construct } from '@aws-cdk/core'; /** * A CodeBuild GPU image running Linux. @@ -113,7 +113,7 @@ export class LinuxGpuBuildImage implements IBindableBuildImage { private _imageId?: string; private constructor(private readonly repositoryName: string, private readonly tag: string, private readonly account: string | undefined) { - this.imageId = Lazy.string({ + this.imageId = core.Lazy.string({ produce: () => { if (this._imageId === undefined) { throw new Error('Make sure this \'LinuxGpuBuildImage\' is used in a CodeBuild Project construct'); diff --git a/packages/@aws-cdk/aws-codebuild/test/integ.aws-deep-learning-container-build-image.expected.json b/packages/@aws-cdk/aws-codebuild/test/integ.aws-deep-learning-container-build-image.expected.json index a926f47c0657d..cee41b06e1ff9 100644 --- a/packages/@aws-cdk/aws-codebuild/test/integ.aws-deep-learning-container-build-image.expected.json +++ b/packages/@aws-cdk/aws-codebuild/test/integ.aws-deep-learning-container-build-image.expected.json @@ -237,6 +237,12 @@ "ca-central-1": { "value": "763104351884" }, + "cn-north-1": { + "value": "727897471807" + }, + "cn-northwest-1": { + "value": "727897471807" + }, "eu-central-1": { "value": "763104351884" }, From 365349025354383416c8e3006feac96b3b893ed2 Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Tue, 14 Dec 2021 15:00:45 +0100 Subject: [PATCH 22/24] Fix test --- .../test/provider-framework/waiter-state-machine.test.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/@aws-cdk/custom-resources/test/provider-framework/waiter-state-machine.test.ts b/packages/@aws-cdk/custom-resources/test/provider-framework/waiter-state-machine.test.ts index acaaeb3a73ef6..f9b683417dc94 100644 --- a/packages/@aws-cdk/custom-resources/test/provider-framework/waiter-state-machine.test.ts +++ b/packages/@aws-cdk/custom-resources/test/provider-framework/waiter-state-machine.test.ts @@ -1,12 +1,15 @@ import '@aws-cdk/assert-internal/jest'; import { Code, Function as lambdaFn, Runtime } from '@aws-cdk/aws-lambda'; import { Duration, Stack } from '@aws-cdk/core'; +import { Node } from 'constructs'; import { WaiterStateMachine } from '../../lib/provider-framework/waiter-state-machine'; describe('state machine', () => { test('contains the needed resources', () => { // GIVEN const stack = new Stack(); + Node.of(stack).setContext('@aws-cdk/core:target-partitions', ['aws', 'aws-cn']); + const isCompleteHandler = new lambdaFn(stack, 'isComplete', { code: Code.fromInline('foo'), runtime: Runtime.NODEJS_12_X, From 25803e4b33dc32c8c237c7ef8fb251f00c67ea84 Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Wed, 15 Dec 2021 11:02:03 +0100 Subject: [PATCH 23/24] Put silly old behavior back --- .../lib/linux-gpu-build-image.ts | 25 +++++++++++-------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/packages/@aws-cdk/aws-codebuild/lib/linux-gpu-build-image.ts b/packages/@aws-cdk/aws-codebuild/lib/linux-gpu-build-image.ts index f1b9dd4f3158f..5fba93bc469bb 100644 --- a/packages/@aws-cdk/aws-codebuild/lib/linux-gpu-build-image.ts +++ b/packages/@aws-cdk/aws-codebuild/lib/linux-gpu-build-image.ts @@ -110,31 +110,34 @@ export class LinuxGpuBuildImage implements IBindableBuildImage { public readonly imagePullPrincipalType?: ImagePullPrincipalType = ImagePullPrincipalType.SERVICE_ROLE; public readonly imageId: string; - private _imageId?: string; + private _imageAccount?: string; - private constructor(private readonly repositoryName: string, private readonly tag: string, private readonly account: string | undefined) { - this.imageId = core.Lazy.string({ + private constructor(private readonly repositoryName: string, tag: string, private readonly account: string | undefined) { + const imageAccount = core.Lazy.string({ produce: () => { - if (this._imageId === undefined) { + if (this._imageAccount === undefined) { throw new Error('Make sure this \'LinuxGpuBuildImage\' is used in a CodeBuild Project construct'); } - return this._imageId; + return this._imageAccount; }, }); + + // The value of imageId below *should* have been `Lazy.stringValue(() => repository.repositoryUriForTag(this.tag))`, + // but we can't change that anymore because someone somewhere might at this point have written code + // to do `image.imageId.includes('pytorch')` and changing this to a full-on token would break them. + this.imageId = `${imageAccount}.dkr.ecr.${core.Aws.REGION}.${core.Aws.URL_SUFFIX}/${repositoryName}:${tag}`; } public bind(scope: Construct, project: IProject, _options: BuildImageBindOptions): BuildImageConfig { + const account = this.account ?? core.Stack.of(scope).regionalFact(FactName.DLC_REPOSITORY_ACCOUNT); const repository = ecr.Repository.fromRepositoryAttributes(scope, 'AwsDlcRepositoryCodeBuild', { repositoryName: this.repositoryName, - repositoryArn: ecr.Repository.arnForLocalRepository( - this.repositoryName, - scope, - this.account ?? core.Stack.of(scope).regionalFact(FactName.DLC_REPOSITORY_ACCOUNT), - ), + repositoryArn: ecr.Repository.arnForLocalRepository(this.repositoryName, scope, account), }); repository.grantPull(project); - this._imageId = repository.repositoryUriForTag(this.tag); + + this._imageAccount = account; return { }; From d918687f87577bf7d447632311cfc61a59f52539 Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Wed, 15 Dec 2021 11:14:01 +0100 Subject: [PATCH 24/24] If `account` was concrete use that immediately in the URI --- packages/@aws-cdk/aws-codebuild/lib/linux-gpu-build-image.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@aws-cdk/aws-codebuild/lib/linux-gpu-build-image.ts b/packages/@aws-cdk/aws-codebuild/lib/linux-gpu-build-image.ts index 5fba93bc469bb..2a836fae59b69 100644 --- a/packages/@aws-cdk/aws-codebuild/lib/linux-gpu-build-image.ts +++ b/packages/@aws-cdk/aws-codebuild/lib/linux-gpu-build-image.ts @@ -113,7 +113,7 @@ export class LinuxGpuBuildImage implements IBindableBuildImage { private _imageAccount?: string; private constructor(private readonly repositoryName: string, tag: string, private readonly account: string | undefined) { - const imageAccount = core.Lazy.string({ + const imageAccount = account ?? core.Lazy.string({ produce: () => { if (this._imageAccount === undefined) { throw new Error('Make sure this \'LinuxGpuBuildImage\' is used in a CodeBuild Project construct');