diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecr/test/integ.repository-lookup.js.snapshot/EcrRepoLookupStack.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecr/test/integ.repository-lookup.js.snapshot/EcrRepoLookupStack.assets.json new file mode 100644 index 0000000000000..47f968ddcf5c6 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecr/test/integ.repository-lookup.js.snapshot/EcrRepoLookupStack.assets.json @@ -0,0 +1,20 @@ +{ + "version": "40.0.0", + "files": { + "694b1f59a97a2cabd43348095c6983d394ce506020298a3a62f3067ae6ce7e18": { + "source": { + "path": "EcrRepoLookupStack.template.json", + "packaging": "file" + }, + "destinations": { + "12345678-test-region": { + "bucketName": "cdk-hnb659fds-assets-12345678-test-region", + "objectKey": "694b1f59a97a2cabd43348095c6983d394ce506020298a3a62f3067ae6ce7e18.json", + "region": "test-region", + "assumeRoleArn": "arn:${AWS::Partition}:iam::12345678:role/cdk-hnb659fds-file-publishing-role-12345678-test-region" + } + } + } + }, + "dockerImages": {} +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecr/test/integ.repository-lookup.js.snapshot/EcrRepoLookupStack.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecr/test/integ.repository-lookup.js.snapshot/EcrRepoLookupStack.template.json new file mode 100644 index 0000000000000..b65cf5070c986 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecr/test/integ.repository-lookup.js.snapshot/EcrRepoLookupStack.template.json @@ -0,0 +1,140 @@ +{ + "Resources": { + "LambdaServiceRoleA8ED4D3B": { + "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" + ] + ] + } + ] + } + }, + "LambdaServiceRoleDefaultPolicyDAE46E21": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "ecr:DescribeImages", + "ecr:DescribeRepositories" + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":ecr:us-east-1:123456789012:repository/DUMMY_ARN" + ] + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "LambdaServiceRoleDefaultPolicyDAE46E21", + "Roles": [ + { + "Ref": "LambdaServiceRoleA8ED4D3B" + } + ] + } + }, + "LambdaD247545B": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "ZipFile": "exports.handler = async function(event, context) { return \"Hello, World!\"; }" + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "LambdaServiceRoleA8ED4D3B", + "Arn" + ] + }, + "Runtime": "nodejs20.x" + }, + "DependsOn": [ + "LambdaServiceRoleDefaultPolicyDAE46E21", + "LambdaServiceRoleA8ED4D3B" + ] + } + }, + "Outputs": { + "RepositoryUri": { + "Value": { + "Fn::Join": [ + "", + [ + "123456789012.dkr.ecr.us-east-1.", + { + "Ref": "AWS::URLSuffix" + }, + "/DUMMY_ARN" + ] + ] + } + } + }, + "Parameters": { + "BootstrapVersion": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/cdk-bootstrap/hnb659fds/version", + "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]" + } + }, + "Rules": { + "CheckBootstrapVersion": { + "Assertions": [ + { + "Assert": { + "Fn::Not": [ + { + "Fn::Contains": [ + [ + "1", + "2", + "3", + "4", + "5" + ], + { + "Ref": "BootstrapVersion" + } + ] + } + ] + }, + "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI." + } + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecr/test/integ.repository-lookup.js.snapshot/EcrRepoLookupTestDefaultTestDeployAssert7F088AF3.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecr/test/integ.repository-lookup.js.snapshot/EcrRepoLookupTestDefaultTestDeployAssert7F088AF3.assets.json new file mode 100644 index 0000000000000..6c5f894f4afdb --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecr/test/integ.repository-lookup.js.snapshot/EcrRepoLookupTestDefaultTestDeployAssert7F088AF3.assets.json @@ -0,0 +1,19 @@ +{ + "version": "40.0.0", + "files": { + "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { + "source": { + "path": "EcrRepoLookupTestDefaultTestDeployAssert7F088AF3.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + } + }, + "dockerImages": {} +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecr/test/integ.repository-lookup.js.snapshot/EcrRepoLookupTestDefaultTestDeployAssert7F088AF3.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecr/test/integ.repository-lookup.js.snapshot/EcrRepoLookupTestDefaultTestDeployAssert7F088AF3.template.json new file mode 100644 index 0000000000000..ad9d0fb73d1dd --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecr/test/integ.repository-lookup.js.snapshot/EcrRepoLookupTestDefaultTestDeployAssert7F088AF3.template.json @@ -0,0 +1,36 @@ +{ + "Parameters": { + "BootstrapVersion": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/cdk-bootstrap/hnb659fds/version", + "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]" + } + }, + "Rules": { + "CheckBootstrapVersion": { + "Assertions": [ + { + "Assert": { + "Fn::Not": [ + { + "Fn::Contains": [ + [ + "1", + "2", + "3", + "4", + "5" + ], + { + "Ref": "BootstrapVersion" + } + ] + } + ] + }, + "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI." + } + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecr/test/integ.repository-lookup.js.snapshot/cdk.out b/packages/@aws-cdk-testing/framework-integ/test/aws-ecr/test/integ.repository-lookup.js.snapshot/cdk.out new file mode 100644 index 0000000000000..1e02a2deb191b --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecr/test/integ.repository-lookup.js.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"40.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecr/test/integ.repository-lookup.js.snapshot/integ.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecr/test/integ.repository-lookup.js.snapshot/integ.json new file mode 100644 index 0000000000000..d7ae2c83ea6d2 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecr/test/integ.repository-lookup.js.snapshot/integ.json @@ -0,0 +1,22 @@ +{ + "enableLookups": true, + "version": "40.0.0", + "testCases": { + "EcrRepoLookupTest/DefaultTest": { + "stacks": [ + "EcrRepoLookupStack" + ], + "hooks": { + "preDeploy": [ + "aws ecr create-repository --repository-name my-repo" + ], + "postDeploy": [ + "aws ecr delete-repository --repository-name my-repo --force" + ] + }, + "stackUpdateWorkflow": false, + "assertionStack": "EcrRepoLookupTest/DefaultTest/DeployAssert", + "assertionStackName": "EcrRepoLookupTestDefaultTestDeployAssert7F088AF3" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecr/test/integ.repository-lookup.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecr/test/integ.repository-lookup.js.snapshot/manifest.json new file mode 100644 index 0000000000000..b81823774aa1a --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecr/test/integ.repository-lookup.js.snapshot/manifest.json @@ -0,0 +1,200 @@ +{ + "version": "40.0.0", + "artifacts": { + "EcrRepoLookupStack.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "EcrRepoLookupStack.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "EcrRepoLookupStack": { + "type": "aws:cloudformation:stack", + "environment": "aws://12345678/test-region", + "properties": { + "templateFile": "EcrRepoLookupStack.template.json", + "terminationProtection": false, + "validateOnSynth": false, + "assumeRoleArn": "arn:${AWS::Partition}:iam::12345678:role/cdk-hnb659fds-deploy-role-12345678-test-region", + "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::12345678:role/cdk-hnb659fds-cfn-exec-role-12345678-test-region", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-12345678-test-region/694b1f59a97a2cabd43348095c6983d394ce506020298a3a62f3067ae6ce7e18.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "EcrRepoLookupStack.assets" + ], + "lookupRole": { + "arn": "arn:${AWS::Partition}:iam::12345678:role/cdk-hnb659fds-lookup-role-12345678-test-region", + "requiresBootstrapStackVersion": 8, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "dependencies": [ + "EcrRepoLookupStack.assets" + ], + "metadata": { + "/EcrRepoLookupStack/Lambda": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + } + ], + "/EcrRepoLookupStack/Lambda/ServiceRole": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + } + ], + "/EcrRepoLookupStack/Lambda/ServiceRole/ImportServiceRole": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + } + ], + "/EcrRepoLookupStack/Lambda/ServiceRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "LambdaServiceRoleA8ED4D3B" + } + ], + "/EcrRepoLookupStack/Lambda/ServiceRole/DefaultPolicy": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + } + ], + "/EcrRepoLookupStack/Lambda/ServiceRole/DefaultPolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "LambdaServiceRoleDefaultPolicyDAE46E21" + } + ], + "/EcrRepoLookupStack/Lambda/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "LambdaD247545B" + } + ], + "/EcrRepoLookupStack/RepositoryUri": [ + { + "type": "aws:cdk:logicalId", + "data": "RepositoryUri" + } + ], + "/EcrRepoLookupStack/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/EcrRepoLookupStack/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "EcrRepoLookupStack" + }, + "EcrRepoLookupTestDefaultTestDeployAssert7F088AF3.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "EcrRepoLookupTestDefaultTestDeployAssert7F088AF3.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "EcrRepoLookupTestDefaultTestDeployAssert7F088AF3": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "EcrRepoLookupTestDefaultTestDeployAssert7F088AF3.template.json", + "terminationProtection": false, + "validateOnSynth": false, + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", + "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "EcrRepoLookupTestDefaultTestDeployAssert7F088AF3.assets" + ], + "lookupRole": { + "arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-${AWS::Region}", + "requiresBootstrapStackVersion": 8, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "dependencies": [ + "EcrRepoLookupTestDefaultTestDeployAssert7F088AF3.assets" + ], + "metadata": { + "/EcrRepoLookupTest/DefaultTest/DeployAssert/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/EcrRepoLookupTest/DefaultTest/DeployAssert/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "EcrRepoLookupTest/DefaultTest/DeployAssert" + }, + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } + } + }, + "missing": [ + { + "key": "cc-api-provider:account=12345678:exactIdentifier=my-repo:propertiesToReturn.0=Arn:region=test-region:typeName=AWS$:$:ECR$:$:Repository", + "provider": "cc-api-provider", + "props": { + "dummyValue": [ + { + "Arn": "arn:${Token[AWS.Partition.3]}:ecr:us-east-1:123456789012:repository/DUMMY_ARN" + } + ], + "account": "12345678", + "region": "test-region", + "typeName": "AWS::ECR::Repository", + "exactIdentifier": "my-repo", + "propertiesToReturn": [ + "Arn" + ], + "lookupRoleArn": "arn:${AWS::Partition}:iam::12345678:role/cdk-hnb659fds-lookup-role-12345678-test-region" + } + } + ] +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecr/test/integ.repository-lookup.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecr/test/integ.repository-lookup.js.snapshot/tree.json new file mode 100644 index 0000000000000..721995796f38d --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecr/test/integ.repository-lookup.js.snapshot/tree.json @@ -0,0 +1 @@ +{"version":"tree-0.1","tree":{"id":"App","path":"","children":{"EcrRepoLookupStack":{"id":"EcrRepoLookupStack","path":"EcrRepoLookupStack","children":{"LookupRepo":{"id":"LookupRepo","path":"EcrRepoLookupStack/LookupRepo","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2","metadata":[]}},"Lambda":{"id":"Lambda","path":"EcrRepoLookupStack/Lambda","children":{"ServiceRole":{"id":"ServiceRole","path":"EcrRepoLookupStack/Lambda/ServiceRole","children":{"ImportServiceRole":{"id":"ImportServiceRole","path":"EcrRepoLookupStack/Lambda/ServiceRole/ImportServiceRole","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2","metadata":["*"]}},"Resource":{"id":"Resource","path":"EcrRepoLookupStack/Lambda/ServiceRole/Resource","attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Role","aws:cdk:cloudformation:props":{"assumeRolePolicyDocument":{"Statement":[{"Action":"sts:AssumeRole","Effect":"Allow","Principal":{"Service":"lambda.amazonaws.com"}}],"Version":"2012-10-17"},"managedPolicyArns":[{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"]]}]}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"DefaultPolicy":{"id":"DefaultPolicy","path":"EcrRepoLookupStack/Lambda/ServiceRole/DefaultPolicy","children":{"Resource":{"id":"Resource","path":"EcrRepoLookupStack/Lambda/ServiceRole/DefaultPolicy/Resource","attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Policy","aws:cdk:cloudformation:props":{"policyDocument":{"Statement":[{"Action":["ecr:DescribeImages","ecr:DescribeRepositories"],"Effect":"Allow","Resource":{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":ecr:us-east-1:123456789012:repository/DUMMY_ARN"]]}}],"Version":"2012-10-17"},"policyName":"LambdaServiceRoleDefaultPolicyDAE46E21","roles":[{"Ref":"LambdaServiceRoleA8ED4D3B"}]}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2","metadata":["*","*","*","*"]}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2","metadata":["*","*","*","*"]}},"Resource":{"id":"Resource","path":"EcrRepoLookupStack/Lambda/Resource","attributes":{"aws:cdk:cloudformation:type":"AWS::Lambda::Function","aws:cdk:cloudformation:props":{"code":{"zipFile":"exports.handler = async function(event, context) { return \"Hello, World!\"; }"},"handler":"index.handler","role":{"Fn::GetAtt":["LambdaServiceRoleA8ED4D3B","Arn"]},"runtime":"nodejs20.x"}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2","metadata":["*"]}},"RepositoryUri":{"id":"RepositoryUri","path":"EcrRepoLookupStack/RepositoryUri","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"BootstrapVersion":{"id":"BootstrapVersion","path":"EcrRepoLookupStack/BootstrapVersion","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"CheckBootstrapVersion":{"id":"CheckBootstrapVersion","path":"EcrRepoLookupStack/CheckBootstrapVersion","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"EcrRepoLookupTest":{"id":"EcrRepoLookupTest","path":"EcrRepoLookupTest","children":{"DefaultTest":{"id":"DefaultTest","path":"EcrRepoLookupTest/DefaultTest","children":{"Default":{"id":"Default","path":"EcrRepoLookupTest/DefaultTest/Default","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"DeployAssert":{"id":"DeployAssert","path":"EcrRepoLookupTest/DefaultTest/DeployAssert","children":{"BootstrapVersion":{"id":"BootstrapVersion","path":"EcrRepoLookupTest/DefaultTest/DeployAssert/BootstrapVersion","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"CheckBootstrapVersion":{"id":"CheckBootstrapVersion","path":"EcrRepoLookupTest/DefaultTest/DeployAssert/CheckBootstrapVersion","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}}},"constructInfo":{"fqn":"@aws-cdk/integ-tests-alpha.IntegTestCase","version":"0.0.0"}}},"constructInfo":{"fqn":"@aws-cdk/integ-tests-alpha.IntegTest","version":"0.0.0"}},"Tree":{"id":"Tree","path":"Tree","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}}} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecr/test/integ.repository-lookup.ts b/packages/@aws-cdk-testing/framework-integ/test/aws-ecr/test/integ.repository-lookup.ts new file mode 100644 index 0000000000000..825ecfeedfb41 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecr/test/integ.repository-lookup.ts @@ -0,0 +1,39 @@ + +import { IntegTest } from '@aws-cdk/integ-tests-alpha'; +import { App, CfnOutput, Stack } from 'aws-cdk-lib'; +import * as ecr from 'aws-cdk-lib/aws-ecr'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; + +const app = new App(); +const repositoryName = 'my-repo'; + +const lookupStack = new Stack(app, 'EcrRepoLookupStack', { + env: { + account: process.env.CDK_INTEG_ACCOUNT ?? process.env.CDK_DEFAULT_ACCOUNT, + region: process.env.CDK_INTEG_REGION ?? process.env.CDK_DEFAULT_REGION, + }, +}); +const lookupRepo = ecr.Repository.fromLookup(lookupStack, 'LookupRepo', { + repositoryName, +}); +const testFunction = new lambda.Function(lookupStack, 'Lambda', { + runtime: lambda.Runtime.NODEJS_20_X, + handler: 'index.handler', + code: lambda.Code.fromInline('exports.handler = async function(event, context) { return "Hello, World!"; }'), +}); +lookupRepo.grantRead(testFunction); + +new CfnOutput(lookupStack, 'RepositoryUri', { + value: lookupRepo.repositoryUri, +}); + +new IntegTest(app, 'EcrRepoLookupTest', { + enableLookups: true, + stackUpdateWorkflow: false, + testCases: [lookupStack], + // create a repository before the test and delete it after + hooks: { + preDeploy: [`aws ecr create-repository --repository-name ${repositoryName}`], + postDeploy: [`aws ecr delete-repository --repository-name ${repositoryName} --force`], + }, +}); diff --git a/packages/aws-cdk-lib/aws-ecr/README.md b/packages/aws-cdk-lib/aws-ecr/README.md index d0ff9fc16cc35..dcbbedf879b17 100644 --- a/packages/aws-cdk-lib/aws-ecr/README.md +++ b/packages/aws-cdk-lib/aws-ecr/README.md @@ -209,6 +209,26 @@ repository.addToResourcePolicy(new iam.PolicyStatement({ })); ``` +## import existing repository + +You can import an existing repository into your CDK app using the `Repository.fromRepositoryArn`, `Repository.fromRepositoryName` or `Repository.fromLookup` method. +These methods take the ARN or the name of the repository and returns an `IRepository` object. + +```ts +// import using repository name +const repositoryFromName = ecr.Repository.fromRepositoryName(this, 'ImportedRepoByName', 'my-repo-name'); + +// import using repository ARN +const repositoryFromArn = ecr.Repository.fromRepositoryArn(this, 'ImportedRepoByArn', 'arn:aws:ecr:us-east-1:123456789012:repository/my-repo-name'); + +// import using repository lookup +// You have to provide either `repositoryArn` or `repositoryName` to lookup the repository +const repositoryFromLookup = ecr.Repository.fromLookup(this, 'ImportedRepoByLookup', { + repositoryArn: 'arn:aws:ecr:us-east-1:123456789012:repository/my-repo-name', + repositoryName: 'my-repo-name', +}); +``` + ## CloudWatch event rules You can publish repository events to a CloudWatch event rule with `onEvent`: diff --git a/packages/aws-cdk-lib/aws-ecr/lib/repository.ts b/packages/aws-cdk-lib/aws-ecr/lib/repository.ts index 713d14ee8c800..bdec659547ecc 100644 --- a/packages/aws-cdk-lib/aws-ecr/lib/repository.ts +++ b/packages/aws-cdk-lib/aws-ecr/lib/repository.ts @@ -5,6 +5,7 @@ import { LifecycleRule, TagStatus } from './lifecycle'; import * as events from '../../aws-events'; import * as iam from '../../aws-iam'; import * as kms from '../../aws-kms'; +import * as cxschema from '../../cloud-assembly-schema'; import { Annotations, ArnFormat, @@ -18,6 +19,8 @@ import { TokenComparison, CustomResource, Aws, + ContextProvider, + Arn, ValidationError, UnscopedValidationError, } from '../../core'; @@ -601,6 +604,24 @@ export interface RepositoryProps { readonly emptyOnDelete?: boolean; } +/** + * Properties for looking up an existing Repository. + */ +export interface RepositoryLookupOptions { + /** + * The name of the repository. + * + * @default - Do not filter on repository name + */ + readonly repositoryName?: string; + /** + * The ARN of the repository. + * + * @default - Do not filter on repository ARN + */ + readonly repositoryArn?: string; +} + export interface RepositoryAttributes { readonly repositoryName: string; readonly repositoryArn: string; @@ -610,6 +631,54 @@ export interface RepositoryAttributes { * Define an ECR repository */ export class Repository extends RepositoryBase { + /** + * Lookup an existing repository + */ + public static fromLookup(scope: Construct, id: string, options: RepositoryLookupOptions): IRepository { + if (Token.isUnresolved(options.repositoryName) || Token.isUnresolved(options.repositoryArn)) { + throw new UnscopedValidationError('Cannot look up a repository with a tokenized name or ARN.'); + } + + if (!options.repositoryArn && !options.repositoryName) { + throw new UnscopedValidationError('At least one of `repositoryName` or `repositoryArn` must be provided.'); + } + + const identifier = options.repositoryName ?? + (options.repositoryArn ? Arn.split(options.repositoryArn, ArnFormat.SLASH_RESOURCE_NAME).resourceName : undefined); + + if (!identifier) { + throw new UnscopedValidationError('Could not determine repository identifier from provided options.'); + } + + const response: {[key: string]: any}[] = ContextProvider.getValue(scope, { + provider: cxschema.ContextProvider.CC_API_PROVIDER, + props: { + typeName: 'AWS::ECR::Repository', + exactIdentifier: identifier, + propertiesToReturn: ['Arn'], + } as cxschema.CcApiContextQuery, + dummyValue: [ + { + Arn: Stack.of(scope).formatArn({ + service: 'ecr', + region: 'us-east-1', + account: '123456789012', + resource: 'repository', + resourceName: 'DUMMY_ARN', + }), + }, + ], + }).value; + + const repository = response[0]; + const repositoryName = Arn.extractResourceName(repository.Arn, 'repository'); + + return this.fromRepositoryAttributes(scope, id, { + repositoryName: repositoryName, + repositoryArn: repository.Arn, + }); + } + /** * Import a repository */ diff --git a/packages/aws-cdk-lib/aws-ecr/test/repository.test.ts b/packages/aws-cdk-lib/aws-ecr/test/repository.test.ts index 766a6d86bb6a4..4647b92696121 100644 --- a/packages/aws-cdk-lib/aws-ecr/test/repository.test.ts +++ b/packages/aws-cdk-lib/aws-ecr/test/repository.test.ts @@ -2,12 +2,146 @@ import { EOL } from 'os'; import { Annotations, Template } from '../../assertions'; import * as iam from '../../aws-iam'; import * as kms from '../../aws-kms'; +import * as cxschema from '../../cloud-assembly-schema'; import * as cdk from '../../core'; import * as ecr from '../lib'; - /* eslint-disable quote-props */ describe('repository', () => { + describe('lookup', () => { + test('return correct repository info by name', () => { + // GIVEN + const resultObjs = [ + { + 'Arn': 'arn:aws:ecr:us-east-1:123456789012:repository/my-repo', + }, + ]; + const value = { + value: resultObjs, + }; + const mock = jest.spyOn(cdk.ContextProvider, 'getValue').mockReturnValue(value); + + // WHEN + const stack = new cdk.Stack(undefined, undefined, { env: { region: 'us-east-1', account: '123456789012' } }); + const repo = ecr.Repository.fromLookup(stack, 'MyRepo', { + repositoryName: 'my-repo', + }); + + // THEN + expect(repo.repositoryName).toEqual('my-repo'); + expect(repo.repositoryArn).toEqual(cdk.Stack.of(repo).formatArn({ + service: 'ecr', + partition: 'aws', + resource: 'repository', + resourceName: 'my-repo', + })); + expect(mock).toHaveBeenCalledWith(stack, { + provider: cxschema.ContextProvider.CC_API_PROVIDER, + props: { + typeName: 'AWS::ECR::Repository', + exactIdentifier: 'my-repo', + propertiesToReturn: [ + 'Arn', + ], + } as cxschema.CcApiContextQuery, + dummyValue: [ + { + 'Arn': ecr.Repository.arnForLocalRepository('DUMMY_ARN', stack), + }, + ], + }); + + mock.mockRestore(); + }); + + test('return correct repository info by arn', () => { + const repoArn = 'arn:aws:ecr:us-east-1:123456789012:repository/my-repo'; + // GIVEN + const resultObjs = [ + { + 'Arn': repoArn, + }, + ]; + const value = { + value: resultObjs, + }; + const mock = jest.spyOn(cdk.ContextProvider, 'getValue').mockReturnValue(value); + + // WHEN + const stack = new cdk.Stack(undefined, undefined, { env: { region: 'us-east-1', account: '123456789012' } }); + const repo = ecr.Repository.fromLookup(stack, 'MyRepo', { + repositoryArn: repoArn, + }); + + // THEN + expect(repo.repositoryName).toEqual('my-repo'); + expect(repo.repositoryArn).toEqual(cdk.Stack.of(repo).formatArn({ + service: 'ecr', + partition: 'aws', + resource: 'repository', + resourceName: 'my-repo', + })); + expect(mock).toHaveBeenCalledWith(stack, { + provider: cxschema.ContextProvider.CC_API_PROVIDER, + props: { + typeName: 'AWS::ECR::Repository', + exactIdentifier: 'my-repo', + propertiesToReturn: [ + 'Arn', + ], + } as cxschema.CcApiContextQuery, + dummyValue: [ + { + 'Arn': ecr.Repository.arnForLocalRepository('DUMMY_ARN', stack), + }, + ], + }); + + mock.mockRestore(); + }); + + test.each([ + { + repositoryArn: 'arn:aws:ecr:us-east-1:123456789012:repository/does-not-exist-repo', + }, + { + repositoryName: 'does-not-exist-repo', + }, + ])('return dummy repository info if not found', (config) => { + // WHEN + const stack = new cdk.Stack(undefined, undefined, { env: { region: 'us-east-1', account: '123456789012' } }); + const repo = ecr.Repository.fromLookup(stack, 'MyRepo', config); + + // THEN + expect(repo.repositoryName).toEqual('DUMMY_ARN'); + expect(repo.repositoryArn).toEqual(ecr.Repository.arnForLocalRepository('DUMMY_ARN', stack)); + }); + + test('throw error if repository name is a token', () => { + // GIVEN + const stack = new cdk.Stack(undefined, undefined, { env: { region: 'us-east-1', account: '123456789012' } }); + const tokenName = new cdk.CfnParameter(stack, 'RepoName'); + expect(() => ecr.Repository.fromLookup(stack, 'MyRepository', { + repositoryName: tokenName.valueAsString, + })).toThrow('Cannot look up a repository with a tokenized name or ARN.'); + }); + + test('throw error if repository arn is a token', () => { + // GIVEN + const stack = new cdk.Stack(undefined, undefined, { env: { region: 'us-east-1', account: '123456789012' } }); + const tokenName = new cdk.CfnParameter(stack, 'RepoArn'); + expect(() => ecr.Repository.fromLookup(stack, 'MyRepository', { + repositoryArn: tokenName.valueAsString, + })).toThrow('Cannot look up a repository with a tokenized name or ARN.'); + }); + + test('throw error if neither repository name nor arn is provided', () => { + // GIVEN + const stack = new cdk.Stack(undefined, undefined, { env: { region: 'us-east-1', account: '123456789012' } }); + expect(() => ecr.Repository.fromLookup(stack, 'MyRepository', {})).toThrow('At least one of `repositoryName` or `repositoryArn` must be provided.'); + }); + }); + test('construct repository', () => { // GIVEN const stack = new cdk.Stack();