diff --git a/API.md b/API.md
index 397cdbd0..a2abd3ae 100644
--- a/API.md
+++ b/API.md
@@ -128,6 +128,119 @@ The tree node.
---
+### ECRDeploymentStep
+
+#### Initializers
+
+```typescript
+import { ECRDeploymentStep } from 'cdk-ecr-deployment'
+
+new ECRDeploymentStep(scope: Construct, id: string, props: ECRDeploymentStepProps)
+```
+
+| **Name** | **Type** | **Description** |
+| --- | --- | --- |
+| scope
| constructs.Construct
| *No description.* |
+| id
| string
| *No description.* |
+| props
| ECRDeploymentStepProps
| *No description.* |
+
+---
+
+##### `scope`Required
+
+- *Type:* constructs.Construct
+
+---
+
+##### `id`Required
+
+- *Type:* string
+
+---
+
+##### `props`Required
+
+- *Type:* ECRDeploymentStepProps
+
+---
+
+#### Methods
+
+| **Name** | **Description** |
+| --- | --- |
+| toString
| Returns a string representation of this construct. |
+
+---
+
+##### `toString`
+
+```typescript
+public toString(): string
+```
+
+Returns a string representation of this construct.
+
+#### Static Functions
+
+| **Name** | **Description** |
+| --- | --- |
+| isConstruct
| Checks if `x` is a construct. |
+
+---
+
+##### `isConstruct`
+
+```typescript
+import { ECRDeploymentStep } from 'cdk-ecr-deployment'
+
+ECRDeploymentStep.isConstruct(x: any)
+```
+
+Checks if `x` is a construct.
+
+Use this method instead of `instanceof` to properly detect `Construct`
+instances, even when the construct library is symlinked.
+
+Explanation: in JavaScript, multiple copies of the `constructs` library on
+disk are seen as independent, completely different libraries. As a
+consequence, the class `Construct` in each copy of the `constructs` library
+is seen as a different class, and an instance of one class will not test as
+`instanceof` the other class. `npm install` will not create installations
+like this, but users may manually symlink construct libraries together or
+use a monorepo tool: in those cases, multiple copies of the `constructs`
+library can be accidentally installed, and `instanceof` will behave
+unpredictably. It is safest to avoid using `instanceof`, and using
+this type-testing method instead.
+
+###### `x`Required
+
+- *Type:* any
+
+Any object.
+
+---
+
+#### Properties
+
+| **Name** | **Type** | **Description** |
+| --- | --- | --- |
+| node
| constructs.Node
| The tree node. |
+
+---
+
+##### `node`Required
+
+```typescript
+public readonly node: Node;
+```
+
+- *Type:* constructs.Node
+
+The tree node.
+
+---
+
+
## Structs
### ECRDeploymentProps
@@ -309,6 +422,215 @@ Only used if 'vpc' is supplied.
---
+### ECRDeploymentStepProps
+
+#### Initializer
+
+```typescript
+import { ECRDeploymentStepProps } from 'cdk-ecr-deployment'
+
+const eCRDeploymentStepProps: ECRDeploymentStepProps = { ... }
+```
+
+#### Properties
+
+| **Name** | **Type** | **Description** |
+| --- | --- | --- |
+| dest
| IImageName
| The destination of the docker image. |
+| src
| IImageName
| The source of the docker image. |
+| buildImage
| string
| Image to use to build Golang lambda for custom resource, if download fails or is not wanted. |
+| environment
| {[ key: string ]: string}
| The environment variable to set. |
+| lambdaHandler
| string
| The name of the lambda handler. |
+| lambdaRuntime
| aws-cdk-lib.aws_lambda.Runtime
| The lambda function runtime environment. |
+| memoryLimit
| number
| The amount of memory (in MiB) to allocate to the AWS Lambda function which replicates the files from the CDK bucket to the destination bucket. |
+| role
| aws-cdk-lib.aws_iam.IRole
| Execution role associated with this function. |
+| securityGroups
| aws-cdk-lib.aws_ec2.SecurityGroup[]
| The list of security groups to associate with the Lambda's network interfaces. |
+| vpc
| aws-cdk-lib.aws_ec2.IVpc
| The VPC network to place the deployment lambda handler in. |
+| vpcSubnets
| aws-cdk-lib.aws_ec2.SubnetSelection
| Where in the VPC to place the deployment lambda handler. |
+| stage
| aws-cdk-lib.aws_codepipeline.IStage
| CodePipeline Stage to include lambda to. |
+| wave
| aws-cdk-lib.pipelines.Wave
| Pipelines Wave to include lambda to. |
+
+---
+
+##### `dest`Required
+
+```typescript
+public readonly dest: IImageName;
+```
+
+- *Type:* IImageName
+
+The destination of the docker image.
+
+---
+
+##### `src`Required
+
+```typescript
+public readonly src: IImageName;
+```
+
+- *Type:* IImageName
+
+The source of the docker image.
+
+---
+
+##### `buildImage`Optional
+
+```typescript
+public readonly buildImage: string;
+```
+
+- *Type:* string
+- *Default:* public.ecr.aws/sam/build-go1.x:latest
+
+Image to use to build Golang lambda for custom resource, if download fails or is not wanted.
+
+Might be needed for local build if all images need to come from own registry.
+
+Note that image should use yum as a package manager and have golang available.
+
+---
+
+##### `environment`Optional
+
+```typescript
+public readonly environment: {[ key: string ]: string};
+```
+
+- *Type:* {[ key: string ]: string}
+
+The environment variable to set.
+
+---
+
+##### `lambdaHandler`Optional
+
+```typescript
+public readonly lambdaHandler: string;
+```
+
+- *Type:* string
+- *Default:* bootstrap
+
+The name of the lambda handler.
+
+---
+
+##### `lambdaRuntime`Optional
+
+```typescript
+public readonly lambdaRuntime: Runtime;
+```
+
+- *Type:* aws-cdk-lib.aws_lambda.Runtime
+- *Default:* lambda.Runtime.PROVIDED_AL2023
+
+The lambda function runtime environment.
+
+---
+
+##### `memoryLimit`Optional
+
+```typescript
+public readonly memoryLimit: number;
+```
+
+- *Type:* number
+- *Default:* 512
+
+The amount of memory (in MiB) to allocate to the AWS Lambda function which replicates the files from the CDK bucket to the destination bucket.
+
+If you are deploying large files, you will need to increase this number
+accordingly.
+
+---
+
+##### `role`Optional
+
+```typescript
+public readonly role: IRole;
+```
+
+- *Type:* aws-cdk-lib.aws_iam.IRole
+- *Default:* A role is automatically created
+
+Execution role associated with this function.
+
+---
+
+##### `securityGroups`Optional
+
+```typescript
+public readonly securityGroups: SecurityGroup[];
+```
+
+- *Type:* aws-cdk-lib.aws_ec2.SecurityGroup[]
+- *Default:* If the function is placed within a VPC and a security group is not specified, either by this or securityGroup prop, a dedicated security group will be created for this function.
+
+The list of security groups to associate with the Lambda's network interfaces.
+
+Only used if 'vpc' is supplied.
+
+---
+
+##### `vpc`Optional
+
+```typescript
+public readonly vpc: IVpc;
+```
+
+- *Type:* aws-cdk-lib.aws_ec2.IVpc
+- *Default:* None
+
+The VPC network to place the deployment lambda handler in.
+
+---
+
+##### `vpcSubnets`Optional
+
+```typescript
+public readonly vpcSubnets: SubnetSelection;
+```
+
+- *Type:* aws-cdk-lib.aws_ec2.SubnetSelection
+- *Default:* the Vpc default strategy if not specified
+
+Where in the VPC to place the deployment lambda handler.
+
+Only used if 'vpc' is supplied.
+
+---
+
+##### `stage`Optional
+
+```typescript
+public readonly stage: IStage;
+```
+
+- *Type:* aws-cdk-lib.aws_codepipeline.IStage
+
+CodePipeline Stage to include lambda to.
+
+If this is set, lambda is invoked in pipeline instead of custom resource.
+
+---
+
+##### `wave`Optional
+
+```typescript
+public readonly wave: Wave;
+```
+
+- *Type:* aws-cdk-lib.pipelines.Wave
+
+Pipelines Wave to include lambda to.
+
+If this is set, lambda is invoked in pipeline instead of custom resource.
+
+---
+
## Classes
### DockerImageName
diff --git a/lambda/go.mod b/lambda/go.mod
index 2aaa90b7..285cc203 100644
--- a/lambda/go.mod
+++ b/lambda/go.mod
@@ -4,8 +4,9 @@ go 1.15
require (
github.com/aws/aws-lambda-go v1.29.0
- github.com/aws/aws-sdk-go-v2 v1.21.0
+ github.com/aws/aws-sdk-go-v2 v1.32.4
github.com/aws/aws-sdk-go-v2/config v1.18.37
+ github.com/aws/aws-sdk-go-v2/service/codepipeline v1.36.3
github.com/aws/aws-sdk-go-v2/service/ecr v1.17.3
github.com/aws/aws-sdk-go-v2/service/s3 v1.35.0
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.19.10
@@ -15,5 +16,4 @@ require (
github.com/pkg/errors v0.9.1
github.com/sirupsen/logrus v1.9.3
github.com/stretchr/testify v1.8.4
- github.com/tchap/go-patricia v2.3.0+incompatible // indirect
)
diff --git a/lambda/go.sum b/lambda/go.sum
index 4a4ca50e..249feb8f 100644
--- a/lambda/go.sum
+++ b/lambda/go.sum
@@ -1097,8 +1097,9 @@ github.com/aws/aws-sdk-go-v2 v1.17.5/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3eP
github.com/aws/aws-sdk-go-v2 v1.17.7/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw=
github.com/aws/aws-sdk-go-v2 v1.18.0/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw=
github.com/aws/aws-sdk-go-v2 v1.18.1/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw=
-github.com/aws/aws-sdk-go-v2 v1.21.0 h1:gMT0IW+03wtYJhRqTVYn0wLzwdnK9sRMcxmtfGzRdJc=
github.com/aws/aws-sdk-go-v2 v1.21.0/go.mod h1:/RfNgGmRxI+iFOB1OeJUyxiU+9s88k3pfHvDagGEp0M=
+github.com/aws/aws-sdk-go-v2 v1.32.4 h1:S13INUiTxgrPueTmrm5DZ+MiAo99zYzHEFh1UNkOxNE=
+github.com/aws/aws-sdk-go-v2 v1.32.4/go.mod h1:2SK5n0a2karNTv5tbP1SjsX0uhttou00v/HpXKM1ZUo=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.3/go.mod h1:gNsR5CaXKmQSSzrmGxmwmct/r+ZBfbxorAuXYsj/M5Y=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10 h1:dK82zF6kkPeCo8J1e+tGx4JdvDIQzj7ygIoLg8WMuGs=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10/go.mod h1:VeTZetY5KRJLuD/7fkQXMU6Mw7H5m/KP2J5Iy9osMno=
@@ -1141,8 +1142,9 @@ github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.29/go.mod h1:Dip3sIGv48
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.31/go.mod h1:QT0BqUvX1Bh2ABdTGnjqEjvjzrCfIniM9Sc8zn9Yndo=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.33/go.mod h1:7i0PF1ME/2eUPFcjkVIwq+DOygHEoK92t5cDqNgYbIw=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.34/go.mod h1:wZpTEecJe0Btj3IYnDx/VlUzor9wm3fJHyvLpQF0VwY=
-github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.41 h1:22dGT7PneFMx4+b3pz7lMTRyN8ZKH7M2cW4GP9yUS2g=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.41/go.mod h1:CrObHAuPneJBlfEJ5T3szXOUkLEThaGfvnhTf33buas=
+github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.23 h1:A2w6m6Tmr+BNXjDsr7M90zkWjsu4JXHwrzPg235STs4=
+github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.23/go.mod h1:35EVp9wyeANdujZruvHiQUAo9E3vbhnIO1mTCAxMlY0=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.3/go.mod h1:ssOhaLpRlh88H3UmEcsBoVKq309quMvm3Ds8e9d4eJM=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.8/go.mod h1:ZIV8GYoC6WLBW5KGs+o4rsc65/ozd+eQ0L31XF5VDwk=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.12/go.mod h1:ckaCVTEdGAxO6KwTGzgskxR1xM+iJW4lxMyDFVda2Fc=
@@ -1152,8 +1154,9 @@ github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.23/go.mod h1:mr6c4cHC+S/
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.25/go.mod h1:zBHOPwhBc3FlQjQJE/D3IfPWiWaQmT06Vq9aNukDo0k=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.27/go.mod h1:UrHnn3QV/d0pBZ6QBAEQcqFLf8FAzLmoUfPVIueOvoM=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.28/go.mod h1:7VRpKQQedkfIEXb4k52I7swUnZP0wohVajJMRn3vsUw=
-github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.35 h1:SijA0mgjV8E+8G45ltVHs0fvKpTj8xmZJ3VwhGKtUSI=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.35/go.mod h1:SJC1nEVVva1g3pHAIdCp7QsRIkMmLAgoDquQ9Rr8kYw=
+github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.23 h1:pgYW9FCabt2M25MoHYCfMrVY2ghiiBKYWUVXfwZs+sU=
+github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.23/go.mod h1:c48kLgzO19wAu3CPkDWC28JbaJ+hfQlsdl7I2+oqIbk=
github.com/aws/aws-sdk-go-v2/internal/ini v1.1.1/go.mod h1:Zy8smImhTdOETZqfyn01iNOe0CNggVbPjCajyaz6Gvg=
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.19/go.mod h1:cVHo8KTuHjShb9V8/VjH3S/8+xPu16qx8fdGwmotJhE=
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.28/go.mod h1:yRZVr/iT0AqyHeep00SZ4YfBAKojXz08w3XMBscdi0c=
@@ -1169,6 +1172,8 @@ github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.23/go.mod h1:uIiFgURZbACBEQJfqTZP
github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.26 h1:wscW+pnn3J1OYnanMnza5ZVYXLX4cKk5rAvUAl4Qu+c=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.26/go.mod h1:MtYiox5gvyB+OyP0Mr0Sm/yzbEAIPL9eijj/ouHAPw0=
github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.8.1/go.mod h1:CM+19rL1+4dFWnOQKwDc7H1KwXTz+h61oUSHyhV0b3o=
+github.com/aws/aws-sdk-go-v2/service/codepipeline v1.36.3 h1:m681OIwRDxyqTjRZR7uR9ZqCyhpXVnLu0tm8ytbZiCY=
+github.com/aws/aws-sdk-go-v2/service/codepipeline v1.36.3/go.mod h1:smc6EfxYZ9b9xD7ll/jcPimS7BuFmwnlsFv/zyUgSj0=
github.com/aws/aws-sdk-go-v2/service/ecr v1.17.3 h1:izPPh0CPwbJMF+KkiOG30+Ptm90VXw15CI4Ipj5cP8M=
github.com/aws/aws-sdk-go-v2/service/ecr v1.17.3/go.mod h1:Yf1qbCbx9ds6+R5R7rXj5c04FSRjpTYEewce6nG9TIc=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.2.1/go.mod h1:v33JQ57i2nekYTA70Mb+O18KeH4KqhdqxTJZNK1zdRE=
@@ -1244,8 +1249,9 @@ github.com/aws/smithy-go v1.12.0/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J
github.com/aws/smithy-go v1.12.1/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA=
github.com/aws/smithy-go v1.13.1/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA=
github.com/aws/smithy-go v1.13.5/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA=
-github.com/aws/smithy-go v1.14.2 h1:MJU9hqBGbvWZdApzpvoF2WAIJDbtjK2NDJSiJP7HblQ=
github.com/aws/smithy-go v1.14.2/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA=
+github.com/aws/smithy-go v1.22.0 h1:uunKnWlcoL3zO7q+gG2Pk53joueEOsnNB28QdMsmiMM=
+github.com/aws/smithy-go v1.22.0/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg=
github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I=
github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
github.com/beeker1121/goque v1.0.3-0.20191103205551-d618510128af/go.mod h1:84CWnaDz4g1tEVnFLnuBigmGK15oPohy0RfvSN8d4eg=
@@ -3341,9 +3347,8 @@ github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 h1:kdXcSzyDtse
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d/go.mod h1:RRCYJbIwD5jmqPI9XoAFR0OcDxqUctll6zUj/+B4S48=
+github.com/tchap/go-patricia v2.2.6+incompatible h1:JvoDL7JSoIP2HDE8AbDH3zC8QBPxmzYe32HHy5yQ+Ck=
github.com/tchap/go-patricia v2.2.6+incompatible/go.mod h1:bmLyhP68RS6kStMGxByiQ23RP/odRBOTVjwp2cDyi6I=
-github.com/tchap/go-patricia v2.3.0+incompatible h1:GkY4dP3cEfEASBPPkWd+AmjYxhmDkqO9/zg7R0lSQRs=
-github.com/tchap/go-patricia v2.3.0+incompatible/go.mod h1:bmLyhP68RS6kStMGxByiQ23RP/odRBOTVjwp2cDyi6I=
github.com/tchap/go-patricia/v2 v2.3.1 h1:6rQp39lgIYZ+MHmdEq4xzuk1t7OdC35z/xm0BGhTkes=
github.com/tchap/go-patricia/v2 v2.3.1/go.mod h1:VZRHKAb53DLaG+nA9EaYYiaEx6YztwDlLElMsnSHD4k=
github.com/tedsuo/ifrit v0.0.0-20180802180643-bea94bb476cc/go.mod h1:eyZnKCc955uh98WQvzOm0dgAeLnf2O0Rz0LPoC5ze+0=
diff --git a/lambda/main.go b/lambda/main.go
index 639d52c6..44b74e9a 100644
--- a/lambda/main.go
+++ b/lambda/main.go
@@ -5,6 +5,7 @@ package main
import (
"context"
+ "encoding/json"
"fmt"
"log"
"os"
@@ -15,7 +16,12 @@ import (
"github.com/sirupsen/logrus"
"github.com/aws/aws-lambda-go/cfn"
+ "github.com/aws/aws-lambda-go/events"
"github.com/aws/aws-lambda-go/lambda"
+ "github.com/aws/aws-sdk-go-v2/aws"
+ "github.com/aws/aws-sdk-go-v2/config"
+ "github.com/aws/aws-sdk-go-v2/service/codepipeline"
+ "github.com/aws/aws-sdk-go-v2/service/codepipeline/types"
_ "cdk-ecr-deployment-handler/s3" // Install s3 transport plugin
)
@@ -45,80 +51,129 @@ func handler(ctx context.Context, event cfn.Event) (physicalResourceID string, d
return physicalResourceID, data, nil
}
if event.RequestType == cfn.RequestCreate || event.RequestType == cfn.RequestUpdate {
- srcImage, err := getStrProps(event.ResourceProperties, SRC_IMAGE)
+ err := copyImage(event.ResourceProperties)
if err != nil {
- return physicalResourceID, data, err
- }
- destImage, err := getStrProps(event.ResourceProperties, DEST_IMAGE)
- if err != nil {
- return physicalResourceID, data, err
- }
- srcCreds, err := getStrPropsDefault(event.ResourceProperties, SRC_CREDS, "")
- if err != nil {
- return physicalResourceID, data, err
- }
- destCreds, err := getStrPropsDefault(event.ResourceProperties, DEST_CREDS, "")
- if err != nil {
- return physicalResourceID, data, err
+ // log.Printf("Copy image failed: %v", err.Error())
+ // return physicalResourceID, data, nil
+ return physicalResourceID, data, fmt.Errorf("copy image failed: %s", err.Error())
}
+ }
- srcCreds, err = parseCreds(srcCreds)
- if err != nil {
- return physicalResourceID, data, err
+ return physicalResourceID, data, nil
+}
+
+// Codepipeline has to get also information about execution back to known if run succeeded or failed
+func codePipelineHandler(ctx context.Context, event events.CodePipelineJobEvent) {
+ cfg, err := config.LoadDefaultConfig(
+ context.Background(),
+ )
+ if err != nil {
+ fmt.Errorf("api client configuration error: %v", err.Error())
+ }
+ c := codepipeline.NewFromConfig(cfg)
+ userParameters := make(map[string]interface{})
+ json.Unmarshal([]byte(event.CodePipelineJob.Data.ActionConfiguration.Configuration.UserParameters), &userParameters)
+ err = copyImage(userParameters)
+ if err != nil {
+ log.Printf("copy image failed: %s", err.Error())
+ results := codepipeline.PutJobFailureResultInput{
+ JobId: &event.CodePipelineJob.ID,
+ FailureDetails: &types.FailureDetails{
+ Message: aws.String(err.Error()),
+ Type: types.FailureTypeJobFailed,
+ },
}
- destCreds, err = parseCreds(destCreds)
- if err != nil {
- return physicalResourceID, data, err
+ _, updateErr := c.PutJobFailureResult(context.TODO(), &results)
+ if updateErr != nil {
+ log.Printf("putting job failure results failed: %s", err.Error())
}
+ return
+ }
- log.Printf("SrcImage: %v DestImage: %v", srcImage, destImage)
+ results := codepipeline.PutJobSuccessResultInput{
+ JobId: &event.CodePipelineJob.ID,
+ ExecutionDetails: &types.ExecutionDetails{
+ Summary: aws.String(fmt.Sprintf("Copied image successfully")),
+ },
+ }
+ _, err = c.PutJobSuccessResult(context.TODO(), &results)
+ if err != nil {
+ log.Printf("putting job success results failed: %s", err.Error())
+ }
+}
- srcRef, err := alltransports.ParseImageName(srcImage)
- if err != nil {
- return physicalResourceID, data, err
- }
- destRef, err := alltransports.ParseImageName(destImage)
- if err != nil {
- return physicalResourceID, data, err
- }
+func copyImage(properties map[string]interface{}) error {
+ srcImage, err := getStrProps(properties, SRC_IMAGE)
+ if err != nil {
+ return err
+ }
+ destImage, err := getStrProps(properties, DEST_IMAGE)
+ if err != nil {
+ return err
+ }
+ srcCreds, err := getStrPropsDefault(properties, SRC_CREDS, "")
+ if err != nil {
+ return err
+ }
+ destCreds, err := getStrPropsDefault(properties, DEST_CREDS, "")
+ if err != nil {
+ return err
+ }
- srcOpts := NewImageOpts(srcImage)
- srcOpts.SetCreds(srcCreds)
- srcCtx, err := srcOpts.NewSystemContext()
- if err != nil {
- return physicalResourceID, data, err
- }
- destOpts := NewImageOpts(destImage)
- destOpts.SetCreds(destCreds)
- destCtx, err := destOpts.NewSystemContext()
- if err != nil {
- return physicalResourceID, data, err
- }
+ srcCreds, err = parseCreds(srcCreds)
+ if err != nil {
+ return err
+ }
+ destCreds, err = parseCreds(destCreds)
+ if err != nil {
+ return err
+ }
- ctx, cancel := newTimeoutContext()
- defer cancel()
- policyContext, err := newPolicyContext()
- if err != nil {
- return physicalResourceID, data, err
- }
- defer policyContext.Destroy()
+ log.Printf("SrcImage: %v DestImage: %v", srcImage, destImage)
- _, err = copy.Image(ctx, policyContext, destRef, srcRef, ©.Options{
- ReportWriter: os.Stdout,
- DestinationCtx: destCtx,
- SourceCtx: srcCtx,
- })
- if err != nil {
- // log.Printf("Copy image failed: %v", err.Error())
- // return physicalResourceID, data, nil
- return physicalResourceID, data, fmt.Errorf("copy image failed: %s", err.Error())
- }
+ srcRef, err := alltransports.ParseImageName(srcImage)
+ if err != nil {
+ return err
+ }
+ destRef, err := alltransports.ParseImageName(destImage)
+ if err != nil {
+ return err
}
- return physicalResourceID, data, nil
+ srcOpts := NewImageOpts(srcImage)
+ srcOpts.SetCreds(srcCreds)
+ srcCtx, err := srcOpts.NewSystemContext()
+ if err != nil {
+ return err
+ }
+ destOpts := NewImageOpts(destImage)
+ destOpts.SetCreds(destCreds)
+ destCtx, err := destOpts.NewSystemContext()
+ if err != nil {
+ return err
+ }
+
+ ctx, cancel := newTimeoutContext()
+ defer cancel()
+ policyContext, err := newPolicyContext()
+ if err != nil {
+ return err
+ }
+ defer policyContext.Destroy()
+
+ _, err = copy.Image(ctx, policyContext, destRef, srcRef, ©.Options{
+ ReportWriter: os.Stdout,
+ DestinationCtx: destCtx,
+ SourceCtx: srcCtx,
+ })
+ return err
}
func main() {
+ invoker := os.Getenv("INVOKER")
+ if invoker == "CODEPIPELINE" {
+ lambda.Start(codePipelineHandler)
+ }
lambda.Start(cfn.LambdaWrap(handler))
}
diff --git a/src/ecr-deployment-step.ts b/src/ecr-deployment-step.ts
new file mode 100644
index 00000000..fcd8b55a
--- /dev/null
+++ b/src/ecr-deployment-step.ts
@@ -0,0 +1,31 @@
+import { aws_lambda as lambda } from 'aws-cdk-lib';
+import { Construct } from 'constructs';
+import { addFunctionPermissions, getFunctionProps, LambdaInvokeStep } from './lambda';
+import { ECRDeploymentStepProps } from './types';
+
+export class ECRDeploymentStep extends Construct {
+
+ private handler: lambda.Function;
+
+ constructor(scope: Construct, id: string, props: ECRDeploymentStepProps) {
+ super(scope, id);
+
+ this.handler = new lambda.Function(this, 'ImageCopyHandler', {
+ ...getFunctionProps(props),
+ environment: {
+ ...props.environment,
+ INVOKER: 'CODEPIPELINE',
+ },
+ });
+
+ const handlerRole = this.handler.role;
+ if (!handlerRole) { throw new Error('lambda.Function should have created a Role'); }
+
+ addFunctionPermissions(handlerRole);
+
+ const factory = new LambdaInvokeStep(this.handler, props, 'ImageCopy');
+
+ props.stage?.addAction(factory.getAction());
+ props.wave?.addPost(factory);
+ }
+}
\ No newline at end of file
diff --git a/src/index.ts b/src/index.ts
index 9ab65116..9ba4b2dc 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -2,133 +2,13 @@
// SPDX-License-Identifier: Apache-2.0
-import * as child_process from 'child_process';
-import * as path from 'path';
-import { aws_ec2 as ec2, aws_iam as iam, aws_lambda as lambda, Duration, CustomResource, Token } from 'aws-cdk-lib';
+import { aws_lambda as lambda, CustomResource, Token } from 'aws-cdk-lib';
import { PolicyStatement, AddToPrincipalPolicyResult } from 'aws-cdk-lib/aws-iam';
-import { RuntimeFamily } from 'aws-cdk-lib/aws-lambda';
import { Construct } from 'constructs';
-import { shouldUsePrebuiltLambda } from './config';
-
-export interface ECRDeploymentProps {
-
- /**
- * Image to use to build Golang lambda for custom resource, if download fails or is not wanted.
- *
- * Might be needed for local build if all images need to come from own registry.
- *
- * Note that image should use yum as a package manager and have golang available.
- *
- * @default - public.ecr.aws/sam/build-go1.x:latest
- */
- readonly buildImage?: string;
- /**
- * The source of the docker image.
- */
- readonly src: IImageName;
-
- /**
- * The destination of the docker image.
- */
- readonly dest: IImageName;
-
- /**
- * The amount of memory (in MiB) to allocate to the AWS Lambda function which
- * replicates the files from the CDK bucket to the destination bucket.
- *
- * If you are deploying large files, you will need to increase this number
- * accordingly.
- *
- * @default - 512
- */
- readonly memoryLimit?: number;
-
- /**
- * Execution role associated with this function
- *
- * @default - A role is automatically created
- */
- readonly role?: iam.IRole;
-
- /**
- * The VPC network to place the deployment lambda handler in.
- *
- * @default - None
- */
- readonly vpc?: ec2.IVpc;
-
- /**
- * Where in the VPC to place the deployment lambda handler.
- * Only used if 'vpc' is supplied.
- *
- * @default - the Vpc default strategy if not specified
- */
- readonly vpcSubnets?: ec2.SubnetSelection;
-
- /**
- * The list of security groups to associate with the Lambda's network interfaces.
- *
- * Only used if 'vpc' is supplied.
- *
- * @default - If the function is placed within a VPC and a security group is
- * not specified, either by this or securityGroup prop, a dedicated security
- * group will be created for this function.
- */
- readonly securityGroups?: ec2.SecurityGroup[];
-
- /**
- * The lambda function runtime environment.
- *
- * @default - lambda.Runtime.PROVIDED_AL2023
- */
- readonly lambdaRuntime?: lambda.Runtime;
-
- /**
- * The name of the lambda handler.
- *
- * @default - bootstrap
- */
- readonly lambdaHandler?: string;
-
- /**
- * The environment variable to set
- */
- readonly environment?: { [key: string]: string };
-}
-
-export interface IImageName {
- /**
- * The uri of the docker image.
- *
- * The uri spec follows https://github.com/containers/skopeo
- */
- readonly uri: string;
-
- /**
- * The credentials of the docker image. Format `user:password` or `AWS Secrets Manager secret arn` or `AWS Secrets Manager secret name`
- */
- creds?: string;
-}
-
-function getCode(buildImage: string): lambda.AssetCode {
- if (shouldUsePrebuiltLambda()) {
- try {
- const installScript = path.join(__dirname, '../lambda/install.js');
- const prebuiltPath = path.join(__dirname, '../lambda/out');
- child_process.execFileSync(process.argv0, [installScript, prebuiltPath]);
-
- return lambda.Code.fromAsset(prebuiltPath);
- } catch (err) {
- console.warn(`Can not get prebuilt lambda: ${err}`);
- }
- }
-
- return lambda.Code.fromDockerBuild(path.join(__dirname, '../lambda'), {
- buildArgs: {
- buildImage,
- },
- });
-}
+import { addFunctionPermissions, getFunctionProps } from './lambda';
+import { ECRDeploymentProps, IImageName } from './types';
+export * from './ecr-deployment-step';
+export * from './types';
export class DockerImageName implements IImageName {
public constructor(private name: string, public creds?: string) { }
@@ -151,53 +31,17 @@ export class ECRDeployment extends Construct {
constructor(scope: Construct, id: string, props: ECRDeploymentProps) {
super(scope, id);
- const memoryLimit = props.memoryLimit ?? 512;
+ const functionProps = getFunctionProps(props);
this.handler = new lambda.SingletonFunction(this, 'CustomResourceHandler', {
- uuid: this.renderSingletonUuid(memoryLimit),
- code: getCode(props.buildImage ?? 'public.ecr.aws/docker/library/golang:1'),
- runtime: props.lambdaRuntime ?? new lambda.Runtime('provided.al2023', RuntimeFamily.OTHER), // not using Runtime.PROVIDED_AL2023 to support older CDK versions (< 2.105.0)
- handler: props.lambdaHandler ?? 'bootstrap',
- environment: props.environment,
+ uuid: this.renderSingletonUuid(functionProps.memorySize),
lambdaPurpose: 'Custom::CDKECRDeployment',
- timeout: Duration.minutes(15),
- role: props.role,
- memorySize: memoryLimit,
- vpc: props.vpc,
- vpcSubnets: props.vpcSubnets,
- securityGroups: props.securityGroups,
+ ...functionProps,
});
const handlerRole = this.handler.role;
if (!handlerRole) { throw new Error('lambda.SingletonFunction should have created a Role'); }
- handlerRole.addToPrincipalPolicy(
- new iam.PolicyStatement({
- effect: iam.Effect.ALLOW,
- actions: [
- 'ecr:GetAuthorizationToken',
- 'ecr:BatchCheckLayerAvailability',
- 'ecr:GetDownloadUrlForLayer',
- 'ecr:GetRepositoryPolicy',
- 'ecr:DescribeRepositories',
- 'ecr:ListImages',
- 'ecr:DescribeImages',
- 'ecr:BatchGetImage',
- 'ecr:ListTagsForResource',
- 'ecr:DescribeImageScanFindings',
- 'ecr:InitiateLayerUpload',
- 'ecr:UploadLayerPart',
- 'ecr:CompleteLayerUpload',
- 'ecr:PutImage',
- ],
- resources: ['*'],
- }));
- handlerRole.addToPrincipalPolicy(new iam.PolicyStatement({
- effect: iam.Effect.ALLOW,
- actions: [
- 's3:GetObject',
- ],
- resources: ['*'],
- }));
+ addFunctionPermissions(handlerRole);
new CustomResource(this, 'CustomResource', {
serviceToken: this.handler.functionArn,
diff --git a/src/lambda.ts b/src/lambda.ts
new file mode 100644
index 00000000..9a7e0249
--- /dev/null
+++ b/src/lambda.ts
@@ -0,0 +1,120 @@
+import * as child_process from 'child_process';
+import * as path from 'path';
+import {
+ aws_codepipeline as codepipeline,
+ aws_codepipeline_actions as codepipeline_actions,
+ Duration,
+ aws_lambda as lambda,
+ pipelines,
+ aws_iam as iam,
+} from 'aws-cdk-lib';
+import { FunctionProps, RuntimeFamily } from 'aws-cdk-lib/aws-lambda';
+import { shouldUsePrebuiltLambda } from './config';
+import { ECRDeploymentProps } from './types';
+
+export class LambdaInvokeStep extends pipelines.Step implements pipelines.ICodePipelineActionFactory {
+ constructor(
+ private readonly handler: lambda.IFunction,
+ private readonly props: ECRDeploymentProps,
+ private readonly lambdaPurpose: string,
+ ) {
+ super('LambdaInvokeStep');
+
+ // This is necessary if your step accepts parametres, like environment variables,
+ // that may contain outputs from other steps. It doesn't matter what the
+ // structure is, as long as it contains the values that may contain outputs.
+ this.discoverReferencedOutputs({
+ env: { /* ... */ },
+ });
+ }
+
+ public produceAction(stage: codepipeline.IStage, _options: pipelines.ProduceActionOptions): pipelines.CodePipelineActionFactoryResult {
+
+
+ // This is where you control what type of Action gets added to the
+ // CodePipeline
+ stage.addAction(this.getAction());
+
+ return { runOrdersConsumed: 1 };
+ }
+
+ public getAction() {
+ return new codepipeline_actions.LambdaInvokeAction({
+ lambda: this.handler,
+ actionName: this.lambdaPurpose,
+ userParameters: {
+ SrcImage: this.props.src.uri,
+ SrcCreds: this.props.src.creds,
+ DestImage: this.props.dest.uri,
+ DestCreds: this.props.dest.creds,
+ },
+ });
+ }
+}
+
+function getCode(buildImage: string): lambda.AssetCode {
+ if (shouldUsePrebuiltLambda()) {
+ try {
+ const installScript = path.join(__dirname, '../lambda/install.js');
+ const prebuiltPath = path.join(__dirname, '../lambda/out');
+ child_process.execFileSync(process.argv0, [installScript, prebuiltPath]);
+
+ return lambda.Code.fromAsset(prebuiltPath);
+ } catch (err) {
+ console.warn(`Can not get prebuilt lambda: ${err}`);
+ }
+ }
+
+ return lambda.Code.fromDockerBuild(path.join(__dirname, '../lambda'), {
+ buildArgs: {
+ buildImage,
+ },
+ });
+}
+
+export function getFunctionProps(props: ECRDeploymentProps): FunctionProps {
+ const memoryLimit = props.memoryLimit ?? 512;
+ return {
+ code: getCode(props.buildImage ?? 'public.ecr.aws/docker/library/golang:1'),
+ runtime: props.lambdaRuntime ?? new lambda.Runtime('provided.al2023', RuntimeFamily.OTHER), // not using Runtime.PROVIDED_AL2023 to support older CDK versions (< 2.105.0)
+ handler: props.lambdaHandler ?? 'bootstrap',
+ environment: props.environment,
+ timeout: Duration.minutes(15),
+ role: props.role,
+ memorySize: memoryLimit,
+ vpc: props.vpc,
+ vpcSubnets: props.vpcSubnets,
+ securityGroups: props.securityGroups,
+ };
+}
+
+export function addFunctionPermissions(role: iam.IRole): void {
+ role.addToPrincipalPolicy(
+ new iam.PolicyStatement({
+ effect: iam.Effect.ALLOW,
+ actions: [
+ 'ecr:GetAuthorizationToken',
+ 'ecr:BatchCheckLayerAvailability',
+ 'ecr:GetDownloadUrlForLayer',
+ 'ecr:GetRepositoryPolicy',
+ 'ecr:DescribeRepositories',
+ 'ecr:ListImages',
+ 'ecr:DescribeImages',
+ 'ecr:BatchGetImage',
+ 'ecr:ListTagsForResource',
+ 'ecr:DescribeImageScanFindings',
+ 'ecr:InitiateLayerUpload',
+ 'ecr:UploadLayerPart',
+ 'ecr:CompleteLayerUpload',
+ 'ecr:PutImage',
+ ],
+ resources: ['*'],
+ }));
+ role.addToPrincipalPolicy(new iam.PolicyStatement({
+ effect: iam.Effect.ALLOW,
+ actions: [
+ 's3:GetObject',
+ ],
+ resources: ['*'],
+ }));
+}
\ No newline at end of file
diff --git a/src/types.ts b/src/types.ts
new file mode 100644
index 00000000..1fdcf95a
--- /dev/null
+++ b/src/types.ts
@@ -0,0 +1,131 @@
+// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+import { aws_ec2 as ec2, aws_iam as iam, aws_lambda as lambda, aws_codepipeline as codepipeline, pipelines } from 'aws-cdk-lib';
+
+export interface ECRDeploymentProps {
+
+ /**
+ * Image to use to build Golang lambda for custom resource, if download fails or is not wanted.
+ *
+ * Might be needed for local build if all images need to come from own registry.
+ *
+ * Note that image should use yum as a package manager and have golang available.
+ *
+ * @default - public.ecr.aws/sam/build-go1.x:latest
+ */
+ readonly buildImage?: string;
+ /**
+ * The source of the docker image.
+ */
+ readonly src: IImageName;
+
+ /**
+ * The destination of the docker image.
+ */
+ readonly dest: IImageName;
+
+ /**
+ * The amount of memory (in MiB) to allocate to the AWS Lambda function which
+ * replicates the files from the CDK bucket to the destination bucket.
+ *
+ * If you are deploying large files, you will need to increase this number
+ * accordingly.
+ *
+ * @default - 512
+ */
+ readonly memoryLimit?: number;
+
+ /**
+ * Execution role associated with this function
+ *
+ * @default - A role is automatically created
+ */
+ readonly role?: iam.IRole;
+
+ /**
+ * The VPC network to place the deployment lambda handler in.
+ *
+ * @default - None
+ */
+ readonly vpc?: ec2.IVpc;
+
+ /**
+ * Where in the VPC to place the deployment lambda handler.
+ * Only used if 'vpc' is supplied.
+ *
+ * @default - the Vpc default strategy if not specified
+ */
+ readonly vpcSubnets?: ec2.SubnetSelection;
+
+ /**
+ * The list of security groups to associate with the Lambda's network interfaces.
+ *
+ * Only used if 'vpc' is supplied.
+ *
+ * @default - If the function is placed within a VPC and a security group is
+ * not specified, either by this or securityGroup prop, a dedicated security
+ * group will be created for this function.
+ */
+ readonly securityGroups?: ec2.SecurityGroup[];
+
+ /**
+ * The lambda function runtime environment.
+ *
+ * @default - lambda.Runtime.PROVIDED_AL2023
+ */
+ readonly lambdaRuntime?: lambda.Runtime;
+
+ /**
+ * The name of the lambda handler.
+ *
+ * @default - bootstrap
+ */
+ readonly lambdaHandler?: string;
+
+ /**
+ * The environment variable to set
+ */
+ readonly environment?: { [key: string]: string };
+}
+
+export interface IImageName {
+ /**
+ * The uri of the docker image.
+ *
+ * The uri spec follows https://github.com/containers/skopeo
+ */
+ readonly uri: string;
+
+ /**
+ * The credentials of the docker image. Format `user:password` or `AWS Secrets Manager secret arn` or `AWS Secrets Manager secret name`
+ */
+ creds?: string;
+}
+
+export class DockerImageName implements IImageName {
+ public constructor(private name: string, public creds?: string) { }
+ public get uri(): string { return `docker://${this.name}`; }
+}
+
+export class S3ArchiveName implements IImageName {
+ private name: string;
+ public constructor(p: string, ref?: string, public creds?: string) {
+ this.name = p;
+ if (ref) {
+ this.name += ':' + ref;
+ }
+ }
+ public get uri(): string { return `s3://${this.name}`; }
+}
+
+export interface ECRDeploymentStepProps extends ECRDeploymentProps {
+ /**
+ * CodePipeline Stage to include lambda to. If this is set, lambda is invoked in pipeline instead of custom resource.
+ */
+ readonly stage?: codepipeline.IStage;
+ /**
+ * Pipelines Wave to include lambda to. If this is set, lambda is invoked in pipeline instead of custom resource.
+ */
+ readonly wave?: pipelines.Wave;
+}
\ No newline at end of file
diff --git a/test/__snapshots__/index.test.ts.snap b/test/__snapshots__/index.test.ts.snap
new file mode 100644
index 00000000..4152ba77
--- /dev/null
+++ b/test/__snapshots__/index.test.ts.snap
@@ -0,0 +1,2299 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`lambda in codepipeline matches snapshot 1`] = `
+Object {
+ "Parameters": Object {
+ "BootstrapVersion": Object {
+ "Default": "/cdk-bootstrap/hnb659fds/version",
+ "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]",
+ "Type": "AWS::SSM::Parameter::Value",
+ },
+ },
+ "Resources": Object {
+ "ImageCopyImageCopyHandlerFBE2CA9D": Object {
+ "DependsOn": Array [
+ "ImageCopyImageCopyHandlerServiceRoleDefaultPolicyD42D3CD6",
+ "ImageCopyImageCopyHandlerServiceRoleDB5F37CC",
+ ],
+ "Properties": Object {
+ "Code": Object {
+ "S3Bucket": Object {
+ "Fn::Sub": "cdk-hnb659fds-assets-\${AWS::AccountId}-\${AWS::Region}",
+ },
+ "S3Key": "dbd7959e3abb97721dfe7f2ae14a4fc2849228b919d3cfdfbfc529026a06d193.zip",
+ },
+ "Environment": Object {
+ "Variables": Object {
+ "INVOKER": "CODEPIPELINE",
+ },
+ },
+ "Handler": "bootstrap",
+ "MemorySize": 512,
+ "Role": Object {
+ "Fn::GetAtt": Array [
+ "ImageCopyImageCopyHandlerServiceRoleDB5F37CC",
+ "Arn",
+ ],
+ },
+ "Runtime": "provided.al2023",
+ "Timeout": 900,
+ },
+ "Type": "AWS::Lambda::Function",
+ },
+ "ImageCopyImageCopyHandlerServiceRoleDB5F37CC": Object {
+ "Properties": Object {
+ "AssumeRolePolicyDocument": Object {
+ "Statement": Array [
+ Object {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Principal": Object {
+ "Service": "lambda.amazonaws.com",
+ },
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "ManagedPolicyArns": Array [
+ Object {
+ "Fn::Join": Array [
+ "",
+ Array [
+ "arn:",
+ Object {
+ "Ref": "AWS::Partition",
+ },
+ ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole",
+ ],
+ ],
+ },
+ ],
+ },
+ "Type": "AWS::IAM::Role",
+ },
+ "ImageCopyImageCopyHandlerServiceRoleDefaultPolicyD42D3CD6": Object {
+ "Properties": Object {
+ "PolicyDocument": Object {
+ "Statement": Array [
+ Object {
+ "Action": Array [
+ "ecr:GetAuthorizationToken",
+ "ecr:BatchCheckLayerAvailability",
+ "ecr:GetDownloadUrlForLayer",
+ "ecr:GetRepositoryPolicy",
+ "ecr:DescribeRepositories",
+ "ecr:ListImages",
+ "ecr:DescribeImages",
+ "ecr:BatchGetImage",
+ "ecr:ListTagsForResource",
+ "ecr:DescribeImageScanFindings",
+ "ecr:InitiateLayerUpload",
+ "ecr:UploadLayerPart",
+ "ecr:CompleteLayerUpload",
+ "ecr:PutImage",
+ ],
+ "Effect": "Allow",
+ "Resource": "*",
+ },
+ Object {
+ "Action": "s3:GetObject",
+ "Effect": "Allow",
+ "Resource": "*",
+ },
+ Object {
+ "Action": Array [
+ "codepipeline:PutJobSuccessResult",
+ "codepipeline:PutJobFailureResult",
+ ],
+ "Effect": "Allow",
+ "Resource": "*",
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "PolicyName": "ImageCopyImageCopyHandlerServiceRoleDefaultPolicyD42D3CD6",
+ "Roles": Array [
+ Object {
+ "Ref": "ImageCopyImageCopyHandlerServiceRoleDB5F37CC",
+ },
+ ],
+ },
+ "Type": "AWS::IAM::Policy",
+ },
+ "NginxRepo42B51311": Object {
+ "DeletionPolicy": "Delete",
+ "Properties": Object {
+ "RepositoryName": "nginx",
+ },
+ "Type": "AWS::ECR::Repository",
+ "UpdateReplacePolicy": "Delete",
+ },
+ "PipelineWithLambdaArtifactsBucket47E296C2": Object {
+ "DeletionPolicy": "Retain",
+ "Properties": Object {
+ "BucketEncryption": Object {
+ "ServerSideEncryptionConfiguration": Array [
+ Object {
+ "ServerSideEncryptionByDefault": Object {
+ "KMSMasterKeyID": Object {
+ "Fn::GetAtt": Array [
+ "PipelineWithLambdaArtifactsBucketEncryptionKey18F9C71E",
+ "Arn",
+ ],
+ },
+ "SSEAlgorithm": "aws:kms",
+ },
+ },
+ ],
+ },
+ "PublicAccessBlockConfiguration": Object {
+ "BlockPublicAcls": true,
+ "BlockPublicPolicy": true,
+ "IgnorePublicAcls": true,
+ "RestrictPublicBuckets": true,
+ },
+ },
+ "Type": "AWS::S3::Bucket",
+ "UpdateReplacePolicy": "Retain",
+ },
+ "PipelineWithLambdaArtifactsBucketEncryptionKey18F9C71E": Object {
+ "DeletionPolicy": "Delete",
+ "Properties": Object {
+ "KeyPolicy": Object {
+ "Statement": Array [
+ Object {
+ "Action": "kms:*",
+ "Effect": "Allow",
+ "Principal": Object {
+ "AWS": Object {
+ "Fn::Join": Array [
+ "",
+ Array [
+ "arn:",
+ Object {
+ "Ref": "AWS::Partition",
+ },
+ ":iam::",
+ Object {
+ "Ref": "AWS::AccountId",
+ },
+ ":root",
+ ],
+ ],
+ },
+ },
+ "Resource": "*",
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ },
+ "Type": "AWS::KMS::Key",
+ "UpdateReplacePolicy": "Delete",
+ },
+ "PipelineWithLambdaArtifactsBucketEncryptionKeyAliasD027891B": Object {
+ "DeletionPolicy": "Delete",
+ "Properties": Object {
+ "AliasName": "alias/codepipeline-pipelinewithlambda",
+ "TargetKeyId": Object {
+ "Fn::GetAtt": Array [
+ "PipelineWithLambdaArtifactsBucketEncryptionKey18F9C71E",
+ "Arn",
+ ],
+ },
+ },
+ "Type": "AWS::KMS::Alias",
+ "UpdateReplacePolicy": "Delete",
+ },
+ "PipelineWithLambdaArtifactsBucketPolicy8219A052": Object {
+ "Properties": Object {
+ "Bucket": Object {
+ "Ref": "PipelineWithLambdaArtifactsBucket47E296C2",
+ },
+ "PolicyDocument": Object {
+ "Statement": Array [
+ Object {
+ "Action": "s3:*",
+ "Condition": Object {
+ "Bool": Object {
+ "aws:SecureTransport": "false",
+ },
+ },
+ "Effect": "Deny",
+ "Principal": Object {
+ "AWS": "*",
+ },
+ "Resource": Array [
+ Object {
+ "Fn::GetAtt": Array [
+ "PipelineWithLambdaArtifactsBucket47E296C2",
+ "Arn",
+ ],
+ },
+ Object {
+ "Fn::Join": Array [
+ "",
+ Array [
+ Object {
+ "Fn::GetAtt": Array [
+ "PipelineWithLambdaArtifactsBucket47E296C2",
+ "Arn",
+ ],
+ },
+ "/*",
+ ],
+ ],
+ },
+ ],
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ },
+ "Type": "AWS::S3::BucketPolicy",
+ },
+ "PipelineWithLambdaCopyImageImageCopyCodePipelineActionRoleB102070F": Object {
+ "Properties": Object {
+ "AssumeRolePolicyDocument": Object {
+ "Statement": Array [
+ Object {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Principal": Object {
+ "AWS": Object {
+ "Fn::Join": Array [
+ "",
+ Array [
+ "arn:",
+ Object {
+ "Ref": "AWS::Partition",
+ },
+ ":iam::",
+ Object {
+ "Ref": "AWS::AccountId",
+ },
+ ":root",
+ ],
+ ],
+ },
+ },
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ },
+ "Type": "AWS::IAM::Role",
+ },
+ "PipelineWithLambdaCopyImageImageCopyCodePipelineActionRoleDefaultPolicy27B08A0A": Object {
+ "Properties": Object {
+ "PolicyDocument": Object {
+ "Statement": Array [
+ Object {
+ "Action": "lambda:ListFunctions",
+ "Effect": "Allow",
+ "Resource": "*",
+ },
+ Object {
+ "Action": "lambda:InvokeFunction",
+ "Effect": "Allow",
+ "Resource": Array [
+ Object {
+ "Fn::GetAtt": Array [
+ "ImageCopyImageCopyHandlerFBE2CA9D",
+ "Arn",
+ ],
+ },
+ Object {
+ "Fn::Join": Array [
+ "",
+ Array [
+ Object {
+ "Fn::GetAtt": Array [
+ "ImageCopyImageCopyHandlerFBE2CA9D",
+ "Arn",
+ ],
+ },
+ ":*",
+ ],
+ ],
+ },
+ ],
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "PolicyName": "PipelineWithLambdaCopyImageImageCopyCodePipelineActionRoleDefaultPolicy27B08A0A",
+ "Roles": Array [
+ Object {
+ "Ref": "PipelineWithLambdaCopyImageImageCopyCodePipelineActionRoleB102070F",
+ },
+ ],
+ },
+ "Type": "AWS::IAM::Policy",
+ },
+ "PipelineWithLambdaEventsRole9045137E": Object {
+ "Properties": Object {
+ "AssumeRolePolicyDocument": Object {
+ "Statement": Array [
+ Object {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Principal": Object {
+ "Service": "events.amazonaws.com",
+ },
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ },
+ "Type": "AWS::IAM::Role",
+ },
+ "PipelineWithLambdaEventsRoleDefaultPolicyDFA38DEA": Object {
+ "Properties": Object {
+ "PolicyDocument": Object {
+ "Statement": Array [
+ Object {
+ "Action": "codepipeline:StartPipelineExecution",
+ "Effect": "Allow",
+ "Resource": Object {
+ "Fn::Join": Array [
+ "",
+ Array [
+ "arn:",
+ Object {
+ "Ref": "AWS::Partition",
+ },
+ ":codepipeline:",
+ Object {
+ "Ref": "AWS::Region",
+ },
+ ":",
+ Object {
+ "Ref": "AWS::AccountId",
+ },
+ ":",
+ Object {
+ "Ref": "PipelineWithLambdaF3D188C7",
+ },
+ ],
+ ],
+ },
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "PolicyName": "PipelineWithLambdaEventsRoleDefaultPolicyDFA38DEA",
+ "Roles": Array [
+ Object {
+ "Ref": "PipelineWithLambdaEventsRole9045137E",
+ },
+ ],
+ },
+ "Type": "AWS::IAM::Policy",
+ },
+ "PipelineWithLambdaF3D188C7": Object {
+ "DependsOn": Array [
+ "PipelineWithLambdaRoleDefaultPolicy93F71456",
+ "PipelineWithLambdaRole23C1246E",
+ ],
+ "Properties": Object {
+ "ArtifactStore": Object {
+ "EncryptionKey": Object {
+ "Id": Object {
+ "Fn::GetAtt": Array [
+ "PipelineWithLambdaArtifactsBucketEncryptionKey18F9C71E",
+ "Arn",
+ ],
+ },
+ "Type": "KMS",
+ },
+ "Location": Object {
+ "Ref": "PipelineWithLambdaArtifactsBucket47E296C2",
+ },
+ "Type": "S3",
+ },
+ "RoleArn": Object {
+ "Fn::GetAtt": Array [
+ "PipelineWithLambdaRole23C1246E",
+ "Arn",
+ ],
+ },
+ "Stages": Array [
+ Object {
+ "Actions": Array [
+ Object {
+ "ActionTypeId": Object {
+ "Category": "Source",
+ "Owner": "AWS",
+ "Provider": "CodeCommit",
+ "Version": "1",
+ },
+ "Configuration": Object {
+ "BranchName": "master",
+ "PollForSourceChanges": false,
+ "RepositoryName": Object {
+ "Fn::GetAtt": Array [
+ "Repo02AC86CF",
+ "Name",
+ ],
+ },
+ },
+ "Name": "Source",
+ "OutputArtifacts": Array [
+ Object {
+ "Name": "Artifact_Source_Source",
+ },
+ ],
+ "RoleArn": Object {
+ "Fn::GetAtt": Array [
+ "PipelineWithLambdaSourceCodePipelineActionRole8A892282",
+ "Arn",
+ ],
+ },
+ "RunOrder": 1,
+ },
+ ],
+ "Name": "Source",
+ },
+ Object {
+ "Actions": Array [
+ Object {
+ "ActionTypeId": Object {
+ "Category": "Invoke",
+ "Owner": "AWS",
+ "Provider": "Lambda",
+ "Version": "1",
+ },
+ "Configuration": Object {
+ "FunctionName": Object {
+ "Ref": "ImageCopyImageCopyHandlerFBE2CA9D",
+ },
+ "UserParameters": Object {
+ "Fn::Join": Array [
+ "",
+ Array [
+ "{\\"SrcImage\\":\\"docker://",
+ Object {
+ "Fn::Select": Array [
+ 4,
+ Object {
+ "Fn::Split": Array [
+ ":",
+ Object {
+ "Fn::GetAtt": Array [
+ "NginxRepo42B51311",
+ "Arn",
+ ],
+ },
+ ],
+ },
+ ],
+ },
+ ".dkr.ecr.",
+ Object {
+ "Fn::Select": Array [
+ 3,
+ Object {
+ "Fn::Split": Array [
+ ":",
+ Object {
+ "Fn::GetAtt": Array [
+ "NginxRepo42B51311",
+ "Arn",
+ ],
+ },
+ ],
+ },
+ ],
+ },
+ ".",
+ Object {
+ "Ref": "AWS::URLSuffix",
+ },
+ "/",
+ Object {
+ "Ref": "NginxRepo42B51311",
+ },
+ ":stable\\",\\"DestImage\\":\\"docker://",
+ Object {
+ "Fn::Select": Array [
+ 4,
+ Object {
+ "Fn::Split": Array [
+ ":",
+ Object {
+ "Fn::GetAtt": Array [
+ "NginxRepo42B51311",
+ "Arn",
+ ],
+ },
+ ],
+ },
+ ],
+ },
+ ".dkr.ecr.",
+ Object {
+ "Fn::Select": Array [
+ 3,
+ Object {
+ "Fn::Split": Array [
+ ":",
+ Object {
+ "Fn::GetAtt": Array [
+ "NginxRepo42B51311",
+ "Arn",
+ ],
+ },
+ ],
+ },
+ ],
+ },
+ ".",
+ Object {
+ "Ref": "AWS::URLSuffix",
+ },
+ "/",
+ Object {
+ "Ref": "NginxRepo42B51311",
+ },
+ ":latest\\"}",
+ ],
+ ],
+ },
+ },
+ "Name": "ImageCopy",
+ "RoleArn": Object {
+ "Fn::GetAtt": Array [
+ "PipelineWithLambdaCopyImageImageCopyCodePipelineActionRoleB102070F",
+ "Arn",
+ ],
+ },
+ "RunOrder": 1,
+ },
+ ],
+ "Name": "CopyImage",
+ },
+ ],
+ },
+ "Type": "AWS::CodePipeline::Pipeline",
+ },
+ "PipelineWithLambdaRole23C1246E": Object {
+ "Properties": Object {
+ "AssumeRolePolicyDocument": Object {
+ "Statement": Array [
+ Object {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Principal": Object {
+ "Service": "codepipeline.amazonaws.com",
+ },
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ },
+ "Type": "AWS::IAM::Role",
+ },
+ "PipelineWithLambdaRoleDefaultPolicy93F71456": Object {
+ "Properties": Object {
+ "PolicyDocument": Object {
+ "Statement": Array [
+ Object {
+ "Action": Array [
+ "s3:GetObject*",
+ "s3:GetBucket*",
+ "s3:List*",
+ "s3:DeleteObject*",
+ "s3:PutObject",
+ "s3:PutObjectLegalHold",
+ "s3:PutObjectRetention",
+ "s3:PutObjectTagging",
+ "s3:PutObjectVersionTagging",
+ "s3:Abort*",
+ ],
+ "Effect": "Allow",
+ "Resource": Array [
+ Object {
+ "Fn::GetAtt": Array [
+ "PipelineWithLambdaArtifactsBucket47E296C2",
+ "Arn",
+ ],
+ },
+ Object {
+ "Fn::Join": Array [
+ "",
+ Array [
+ Object {
+ "Fn::GetAtt": Array [
+ "PipelineWithLambdaArtifactsBucket47E296C2",
+ "Arn",
+ ],
+ },
+ "/*",
+ ],
+ ],
+ },
+ ],
+ },
+ Object {
+ "Action": Array [
+ "kms:Decrypt",
+ "kms:DescribeKey",
+ "kms:Encrypt",
+ "kms:ReEncrypt*",
+ "kms:GenerateDataKey*",
+ ],
+ "Effect": "Allow",
+ "Resource": Object {
+ "Fn::GetAtt": Array [
+ "PipelineWithLambdaArtifactsBucketEncryptionKey18F9C71E",
+ "Arn",
+ ],
+ },
+ },
+ Object {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Resource": Object {
+ "Fn::GetAtt": Array [
+ "PipelineWithLambdaSourceCodePipelineActionRole8A892282",
+ "Arn",
+ ],
+ },
+ },
+ Object {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Resource": Object {
+ "Fn::GetAtt": Array [
+ "PipelineWithLambdaCopyImageImageCopyCodePipelineActionRoleB102070F",
+ "Arn",
+ ],
+ },
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "PolicyName": "PipelineWithLambdaRoleDefaultPolicy93F71456",
+ "Roles": Array [
+ Object {
+ "Ref": "PipelineWithLambdaRole23C1246E",
+ },
+ ],
+ },
+ "Type": "AWS::IAM::Policy",
+ },
+ "PipelineWithLambdaSourceCodePipelineActionRole8A892282": Object {
+ "Properties": Object {
+ "AssumeRolePolicyDocument": Object {
+ "Statement": Array [
+ Object {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Principal": Object {
+ "AWS": Object {
+ "Fn::Join": Array [
+ "",
+ Array [
+ "arn:",
+ Object {
+ "Ref": "AWS::Partition",
+ },
+ ":iam::",
+ Object {
+ "Ref": "AWS::AccountId",
+ },
+ ":root",
+ ],
+ ],
+ },
+ },
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ },
+ "Type": "AWS::IAM::Role",
+ },
+ "PipelineWithLambdaSourceCodePipelineActionRoleDefaultPolicy66644772": Object {
+ "Properties": Object {
+ "PolicyDocument": Object {
+ "Statement": Array [
+ Object {
+ "Action": Array [
+ "s3:GetObject*",
+ "s3:GetBucket*",
+ "s3:List*",
+ "s3:DeleteObject*",
+ "s3:PutObject",
+ "s3:PutObjectLegalHold",
+ "s3:PutObjectRetention",
+ "s3:PutObjectTagging",
+ "s3:PutObjectVersionTagging",
+ "s3:Abort*",
+ ],
+ "Effect": "Allow",
+ "Resource": Array [
+ Object {
+ "Fn::GetAtt": Array [
+ "PipelineWithLambdaArtifactsBucket47E296C2",
+ "Arn",
+ ],
+ },
+ Object {
+ "Fn::Join": Array [
+ "",
+ Array [
+ Object {
+ "Fn::GetAtt": Array [
+ "PipelineWithLambdaArtifactsBucket47E296C2",
+ "Arn",
+ ],
+ },
+ "/*",
+ ],
+ ],
+ },
+ ],
+ },
+ Object {
+ "Action": Array [
+ "kms:Decrypt",
+ "kms:DescribeKey",
+ "kms:Encrypt",
+ "kms:ReEncrypt*",
+ "kms:GenerateDataKey*",
+ ],
+ "Effect": "Allow",
+ "Resource": Object {
+ "Fn::GetAtt": Array [
+ "PipelineWithLambdaArtifactsBucketEncryptionKey18F9C71E",
+ "Arn",
+ ],
+ },
+ },
+ Object {
+ "Action": Array [
+ "codecommit:GetBranch",
+ "codecommit:GetCommit",
+ "codecommit:UploadArchive",
+ "codecommit:GetUploadArchiveStatus",
+ "codecommit:CancelUploadArchive",
+ ],
+ "Effect": "Allow",
+ "Resource": Object {
+ "Fn::GetAtt": Array [
+ "Repo02AC86CF",
+ "Arn",
+ ],
+ },
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "PolicyName": "PipelineWithLambdaSourceCodePipelineActionRoleDefaultPolicy66644772",
+ "Roles": Array [
+ Object {
+ "Ref": "PipelineWithLambdaSourceCodePipelineActionRole8A892282",
+ },
+ ],
+ },
+ "Type": "AWS::IAM::Policy",
+ },
+ "Repo02AC86CF": Object {
+ "Properties": Object {
+ "RepositoryName": "test-repo",
+ },
+ "Type": "AWS::CodeCommit::Repository",
+ },
+ "RepoPipelineWithLambdaEventRuleDE3CEAA4": Object {
+ "Properties": Object {
+ "EventPattern": Object {
+ "detail": Object {
+ "event": Array [
+ "referenceCreated",
+ "referenceUpdated",
+ ],
+ "referenceName": Array [
+ "master",
+ ],
+ },
+ "detail-type": Array [
+ "CodeCommit Repository State Change",
+ ],
+ "resources": Array [
+ Object {
+ "Fn::GetAtt": Array [
+ "Repo02AC86CF",
+ "Arn",
+ ],
+ },
+ ],
+ "source": Array [
+ "aws.codecommit",
+ ],
+ },
+ "State": "ENABLED",
+ "Targets": Array [
+ Object {
+ "Arn": Object {
+ "Fn::Join": Array [
+ "",
+ Array [
+ "arn:",
+ Object {
+ "Ref": "AWS::Partition",
+ },
+ ":codepipeline:",
+ Object {
+ "Ref": "AWS::Region",
+ },
+ ":",
+ Object {
+ "Ref": "AWS::AccountId",
+ },
+ ":",
+ Object {
+ "Ref": "PipelineWithLambdaF3D188C7",
+ },
+ ],
+ ],
+ },
+ "Id": "Target0",
+ "RoleArn": Object {
+ "Fn::GetAtt": Array [
+ "PipelineWithLambdaEventsRole9045137E",
+ "Arn",
+ ],
+ },
+ },
+ ],
+ },
+ "Type": "AWS::Events::Rule",
+ },
+ },
+ "Rules": Object {
+ "CheckBootstrapVersion": Object {
+ "Assertions": Array [
+ Object {
+ "Assert": Object {
+ "Fn::Not": Array [
+ Object {
+ "Fn::Contains": Array [
+ Array [
+ "1",
+ "2",
+ "3",
+ "4",
+ "5",
+ ],
+ Object {
+ "Ref": "BootstrapVersion",
+ },
+ ],
+ },
+ ],
+ },
+ "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI.",
+ },
+ ],
+ },
+ },
+}
+`;
+
+exports[`lambda in pipelines pipeline matches snapshot 1`] = `
+Object {
+ "Parameters": Object {
+ "BootstrapVersion": Object {
+ "Default": "/cdk-bootstrap/hnb659fds/version",
+ "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]",
+ "Type": "AWS::SSM::Parameter::Value",
+ },
+ },
+ "Resources": Object {
+ "ImageCopyImageCopyHandlerFBE2CA9D": Object {
+ "DependsOn": Array [
+ "ImageCopyImageCopyHandlerServiceRoleDefaultPolicyD42D3CD6",
+ "ImageCopyImageCopyHandlerServiceRoleDB5F37CC",
+ ],
+ "Properties": Object {
+ "Code": Object {
+ "S3Bucket": Object {
+ "Fn::Sub": "cdk-hnb659fds-assets-\${AWS::AccountId}-\${AWS::Region}",
+ },
+ "S3Key": "dbd7959e3abb97721dfe7f2ae14a4fc2849228b919d3cfdfbfc529026a06d193.zip",
+ },
+ "Environment": Object {
+ "Variables": Object {
+ "INVOKER": "CODEPIPELINE",
+ },
+ },
+ "Handler": "bootstrap",
+ "MemorySize": 512,
+ "Role": Object {
+ "Fn::GetAtt": Array [
+ "ImageCopyImageCopyHandlerServiceRoleDB5F37CC",
+ "Arn",
+ ],
+ },
+ "Runtime": "provided.al2023",
+ "Timeout": 900,
+ },
+ "Type": "AWS::Lambda::Function",
+ },
+ "ImageCopyImageCopyHandlerServiceRoleDB5F37CC": Object {
+ "Properties": Object {
+ "AssumeRolePolicyDocument": Object {
+ "Statement": Array [
+ Object {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Principal": Object {
+ "Service": "lambda.amazonaws.com",
+ },
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "ManagedPolicyArns": Array [
+ Object {
+ "Fn::Join": Array [
+ "",
+ Array [
+ "arn:",
+ Object {
+ "Ref": "AWS::Partition",
+ },
+ ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole",
+ ],
+ ],
+ },
+ ],
+ },
+ "Type": "AWS::IAM::Role",
+ },
+ "ImageCopyImageCopyHandlerServiceRoleDefaultPolicyD42D3CD6": Object {
+ "Properties": Object {
+ "PolicyDocument": Object {
+ "Statement": Array [
+ Object {
+ "Action": Array [
+ "ecr:GetAuthorizationToken",
+ "ecr:BatchCheckLayerAvailability",
+ "ecr:GetDownloadUrlForLayer",
+ "ecr:GetRepositoryPolicy",
+ "ecr:DescribeRepositories",
+ "ecr:ListImages",
+ "ecr:DescribeImages",
+ "ecr:BatchGetImage",
+ "ecr:ListTagsForResource",
+ "ecr:DescribeImageScanFindings",
+ "ecr:InitiateLayerUpload",
+ "ecr:UploadLayerPart",
+ "ecr:CompleteLayerUpload",
+ "ecr:PutImage",
+ ],
+ "Effect": "Allow",
+ "Resource": "*",
+ },
+ Object {
+ "Action": "s3:GetObject",
+ "Effect": "Allow",
+ "Resource": "*",
+ },
+ Object {
+ "Action": Array [
+ "codepipeline:PutJobSuccessResult",
+ "codepipeline:PutJobFailureResult",
+ ],
+ "Effect": "Allow",
+ "Resource": "*",
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "PolicyName": "ImageCopyImageCopyHandlerServiceRoleDefaultPolicyD42D3CD6",
+ "Roles": Array [
+ Object {
+ "Ref": "ImageCopyImageCopyHandlerServiceRoleDB5F37CC",
+ },
+ ],
+ },
+ "Type": "AWS::IAM::Policy",
+ },
+ "NginxRepo42B51311": Object {
+ "DeletionPolicy": "Delete",
+ "Properties": Object {
+ "RepositoryName": "nginx",
+ },
+ "Type": "AWS::ECR::Repository",
+ "UpdateReplacePolicy": "Delete",
+ },
+ "Repo02AC86CF": Object {
+ "Properties": Object {
+ "RepositoryName": "test-repo",
+ },
+ "Type": "AWS::CodeCommit::Repository",
+ },
+ "RepopipelinesPipeline19AAB9B8EventRule6357EE85": Object {
+ "Properties": Object {
+ "EventPattern": Object {
+ "detail": Object {
+ "event": Array [
+ "referenceCreated",
+ "referenceUpdated",
+ ],
+ "referenceName": Array [
+ "master",
+ ],
+ },
+ "detail-type": Array [
+ "CodeCommit Repository State Change",
+ ],
+ "resources": Array [
+ Object {
+ "Fn::GetAtt": Array [
+ "Repo02AC86CF",
+ "Arn",
+ ],
+ },
+ ],
+ "source": Array [
+ "aws.codecommit",
+ ],
+ },
+ "State": "ENABLED",
+ "Targets": Array [
+ Object {
+ "Arn": Object {
+ "Fn::Join": Array [
+ "",
+ Array [
+ "arn:",
+ Object {
+ "Ref": "AWS::Partition",
+ },
+ ":codepipeline:",
+ Object {
+ "Ref": "AWS::Region",
+ },
+ ":",
+ Object {
+ "Ref": "AWS::AccountId",
+ },
+ ":",
+ Object {
+ "Ref": "pipelinesPipelineEAE3F1AF",
+ },
+ ],
+ ],
+ },
+ "Id": "Target0",
+ "RoleArn": Object {
+ "Fn::GetAtt": Array [
+ "pipelinesPipelineEventsRoleF14AE9B6",
+ "Arn",
+ ],
+ },
+ },
+ ],
+ },
+ "Type": "AWS::Events::Rule",
+ },
+ "pipelinesCodeBuildActionRole0A34FFD8": Object {
+ "Properties": Object {
+ "AssumeRolePolicyDocument": Object {
+ "Statement": Array [
+ Object {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Principal": Object {
+ "AWS": Object {
+ "Fn::GetAtt": Array [
+ "pipelinesPipelineRole3396D699",
+ "Arn",
+ ],
+ },
+ },
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ },
+ "Type": "AWS::IAM::Role",
+ },
+ "pipelinesCodeBuildActionRoleDefaultPolicy1075D2D6": Object {
+ "Properties": Object {
+ "PolicyDocument": Object {
+ "Statement": Array [
+ Object {
+ "Action": Array [
+ "codebuild:BatchGetBuilds",
+ "codebuild:StartBuild",
+ "codebuild:StopBuild",
+ ],
+ "Effect": "Allow",
+ "Resource": Object {
+ "Fn::GetAtt": Array [
+ "pipelinesPipelineBuildsynthCdkBuildProjectC3D1D808",
+ "Arn",
+ ],
+ },
+ },
+ Object {
+ "Action": Array [
+ "codebuild:BatchGetBuilds",
+ "codebuild:StartBuild",
+ "codebuild:StopBuild",
+ ],
+ "Effect": "Allow",
+ "Resource": Object {
+ "Fn::GetAtt": Array [
+ "pipelinesUpdatePipelineSelfMutationFA94E664",
+ "Arn",
+ ],
+ },
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "PolicyName": "pipelinesCodeBuildActionRoleDefaultPolicy1075D2D6",
+ "Roles": Array [
+ Object {
+ "Ref": "pipelinesCodeBuildActionRole0A34FFD8",
+ },
+ ],
+ },
+ "Type": "AWS::IAM::Policy",
+ },
+ "pipelinesPipelineArtifactsBucket27498DB8": Object {
+ "DeletionPolicy": "Retain",
+ "Properties": Object {
+ "BucketEncryption": Object {
+ "ServerSideEncryptionConfiguration": Array [
+ Object {
+ "ServerSideEncryptionByDefault": Object {
+ "SSEAlgorithm": "aws:kms",
+ },
+ },
+ ],
+ },
+ "PublicAccessBlockConfiguration": Object {
+ "BlockPublicAcls": true,
+ "BlockPublicPolicy": true,
+ "IgnorePublicAcls": true,
+ "RestrictPublicBuckets": true,
+ },
+ },
+ "Type": "AWS::S3::Bucket",
+ "UpdateReplacePolicy": "Retain",
+ },
+ "pipelinesPipelineArtifactsBucketPolicy2E6820BE": Object {
+ "Properties": Object {
+ "Bucket": Object {
+ "Ref": "pipelinesPipelineArtifactsBucket27498DB8",
+ },
+ "PolicyDocument": Object {
+ "Statement": Array [
+ Object {
+ "Action": "s3:*",
+ "Condition": Object {
+ "Bool": Object {
+ "aws:SecureTransport": "false",
+ },
+ },
+ "Effect": "Deny",
+ "Principal": Object {
+ "AWS": "*",
+ },
+ "Resource": Array [
+ Object {
+ "Fn::GetAtt": Array [
+ "pipelinesPipelineArtifactsBucket27498DB8",
+ "Arn",
+ ],
+ },
+ Object {
+ "Fn::Join": Array [
+ "",
+ Array [
+ Object {
+ "Fn::GetAtt": Array [
+ "pipelinesPipelineArtifactsBucket27498DB8",
+ "Arn",
+ ],
+ },
+ "/*",
+ ],
+ ],
+ },
+ ],
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ },
+ "Type": "AWS::S3::BucketPolicy",
+ },
+ "pipelinesPipelineBuildsynthCdkBuildProjectC3D1D808": Object {
+ "Properties": Object {
+ "Artifacts": Object {
+ "Type": "CODEPIPELINE",
+ },
+ "Cache": Object {
+ "Type": "NO_CACHE",
+ },
+ "Description": "Pipeline step Default/Pipeline/Build/synth",
+ "EncryptionKey": "alias/aws/s3",
+ "Environment": Object {
+ "ComputeType": "BUILD_GENERAL1_SMALL",
+ "Image": "aws/codebuild/standard:7.0",
+ "ImagePullCredentialsType": "CODEBUILD",
+ "PrivilegedMode": false,
+ "Type": "LINUX_CONTAINER",
+ },
+ "ServiceRole": Object {
+ "Fn::GetAtt": Array [
+ "pipelinesPipelineBuildsynthCdkBuildProjectRole501C3E99",
+ "Arn",
+ ],
+ },
+ "Source": Object {
+ "BuildSpec": "{
+ \\"version\\": \\"0.2\\",
+ \\"phases\\": {
+ \\"build\\": {
+ \\"commands\\": [
+ \\"mkdir cdk.out\\",
+ \\"touch cdk.out/test\\"
+ ]
+ }
+ },
+ \\"artifacts\\": {
+ \\"base-directory\\": \\"cdk.out\\",
+ \\"files\\": \\"**/*\\"
+ }
+}",
+ "Type": "CODEPIPELINE",
+ },
+ },
+ "Type": "AWS::CodeBuild::Project",
+ },
+ "pipelinesPipelineBuildsynthCdkBuildProjectRole501C3E99": Object {
+ "Properties": Object {
+ "AssumeRolePolicyDocument": Object {
+ "Statement": Array [
+ Object {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Principal": Object {
+ "Service": "codebuild.amazonaws.com",
+ },
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ },
+ "Type": "AWS::IAM::Role",
+ },
+ "pipelinesPipelineBuildsynthCdkBuildProjectRoleDefaultPolicy0CFABA24": Object {
+ "Properties": Object {
+ "PolicyDocument": Object {
+ "Statement": Array [
+ Object {
+ "Action": Array [
+ "logs:CreateLogGroup",
+ "logs:CreateLogStream",
+ "logs:PutLogEvents",
+ ],
+ "Effect": "Allow",
+ "Resource": Array [
+ Object {
+ "Fn::Join": Array [
+ "",
+ Array [
+ "arn:",
+ Object {
+ "Ref": "AWS::Partition",
+ },
+ ":logs:",
+ Object {
+ "Ref": "AWS::Region",
+ },
+ ":",
+ Object {
+ "Ref": "AWS::AccountId",
+ },
+ ":log-group:/aws/codebuild/",
+ Object {
+ "Ref": "pipelinesPipelineBuildsynthCdkBuildProjectC3D1D808",
+ },
+ ],
+ ],
+ },
+ Object {
+ "Fn::Join": Array [
+ "",
+ Array [
+ "arn:",
+ Object {
+ "Ref": "AWS::Partition",
+ },
+ ":logs:",
+ Object {
+ "Ref": "AWS::Region",
+ },
+ ":",
+ Object {
+ "Ref": "AWS::AccountId",
+ },
+ ":log-group:/aws/codebuild/",
+ Object {
+ "Ref": "pipelinesPipelineBuildsynthCdkBuildProjectC3D1D808",
+ },
+ ":*",
+ ],
+ ],
+ },
+ ],
+ },
+ Object {
+ "Action": Array [
+ "codebuild:CreateReportGroup",
+ "codebuild:CreateReport",
+ "codebuild:UpdateReport",
+ "codebuild:BatchPutTestCases",
+ "codebuild:BatchPutCodeCoverages",
+ ],
+ "Effect": "Allow",
+ "Resource": Object {
+ "Fn::Join": Array [
+ "",
+ Array [
+ "arn:",
+ Object {
+ "Ref": "AWS::Partition",
+ },
+ ":codebuild:",
+ Object {
+ "Ref": "AWS::Region",
+ },
+ ":",
+ Object {
+ "Ref": "AWS::AccountId",
+ },
+ ":report-group/",
+ Object {
+ "Ref": "pipelinesPipelineBuildsynthCdkBuildProjectC3D1D808",
+ },
+ "-*",
+ ],
+ ],
+ },
+ },
+ Object {
+ "Action": Array [
+ "s3:GetObject*",
+ "s3:GetBucket*",
+ "s3:List*",
+ "s3:DeleteObject*",
+ "s3:PutObject",
+ "s3:PutObjectLegalHold",
+ "s3:PutObjectRetention",
+ "s3:PutObjectTagging",
+ "s3:PutObjectVersionTagging",
+ "s3:Abort*",
+ ],
+ "Effect": "Allow",
+ "Resource": Array [
+ Object {
+ "Fn::GetAtt": Array [
+ "pipelinesPipelineArtifactsBucket27498DB8",
+ "Arn",
+ ],
+ },
+ Object {
+ "Fn::Join": Array [
+ "",
+ Array [
+ Object {
+ "Fn::GetAtt": Array [
+ "pipelinesPipelineArtifactsBucket27498DB8",
+ "Arn",
+ ],
+ },
+ "/*",
+ ],
+ ],
+ },
+ ],
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "PolicyName": "pipelinesPipelineBuildsynthCdkBuildProjectRoleDefaultPolicy0CFABA24",
+ "Roles": Array [
+ Object {
+ "Ref": "pipelinesPipelineBuildsynthCdkBuildProjectRole501C3E99",
+ },
+ ],
+ },
+ "Type": "AWS::IAM::Policy",
+ },
+ "pipelinesPipelineCopyImageImageCopyCodePipelineActionRoleBCA09BEC": Object {
+ "Properties": Object {
+ "AssumeRolePolicyDocument": Object {
+ "Statement": Array [
+ Object {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Principal": Object {
+ "AWS": Object {
+ "Fn::Join": Array [
+ "",
+ Array [
+ "arn:",
+ Object {
+ "Ref": "AWS::Partition",
+ },
+ ":iam::",
+ Object {
+ "Ref": "AWS::AccountId",
+ },
+ ":root",
+ ],
+ ],
+ },
+ },
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ },
+ "Type": "AWS::IAM::Role",
+ },
+ "pipelinesPipelineCopyImageImageCopyCodePipelineActionRoleDefaultPolicyF21FF0CC": Object {
+ "Properties": Object {
+ "PolicyDocument": Object {
+ "Statement": Array [
+ Object {
+ "Action": "lambda:ListFunctions",
+ "Effect": "Allow",
+ "Resource": "*",
+ },
+ Object {
+ "Action": "lambda:InvokeFunction",
+ "Effect": "Allow",
+ "Resource": Array [
+ Object {
+ "Fn::GetAtt": Array [
+ "ImageCopyImageCopyHandlerFBE2CA9D",
+ "Arn",
+ ],
+ },
+ Object {
+ "Fn::Join": Array [
+ "",
+ Array [
+ Object {
+ "Fn::GetAtt": Array [
+ "ImageCopyImageCopyHandlerFBE2CA9D",
+ "Arn",
+ ],
+ },
+ ":*",
+ ],
+ ],
+ },
+ ],
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "PolicyName": "pipelinesPipelineCopyImageImageCopyCodePipelineActionRoleDefaultPolicyF21FF0CC",
+ "Roles": Array [
+ Object {
+ "Ref": "pipelinesPipelineCopyImageImageCopyCodePipelineActionRoleBCA09BEC",
+ },
+ ],
+ },
+ "Type": "AWS::IAM::Policy",
+ },
+ "pipelinesPipelineEAE3F1AF": Object {
+ "DependsOn": Array [
+ "pipelinesPipelineRoleDefaultPolicy8A18F220",
+ "pipelinesPipelineRole3396D699",
+ ],
+ "Properties": Object {
+ "ArtifactStore": Object {
+ "Location": Object {
+ "Ref": "pipelinesPipelineArtifactsBucket27498DB8",
+ },
+ "Type": "S3",
+ },
+ "PipelineType": "V1",
+ "RestartExecutionOnUpdate": true,
+ "RoleArn": Object {
+ "Fn::GetAtt": Array [
+ "pipelinesPipelineRole3396D699",
+ "Arn",
+ ],
+ },
+ "Stages": Array [
+ Object {
+ "Actions": Array [
+ Object {
+ "ActionTypeId": Object {
+ "Category": "Source",
+ "Owner": "AWS",
+ "Provider": "CodeCommit",
+ "Version": "1",
+ },
+ "Configuration": Object {
+ "BranchName": "master",
+ "PollForSourceChanges": false,
+ "RepositoryName": Object {
+ "Fn::GetAtt": Array [
+ "Repo02AC86CF",
+ "Name",
+ ],
+ },
+ },
+ "Name": Object {
+ "Fn::GetAtt": Array [
+ "Repo02AC86CF",
+ "Name",
+ ],
+ },
+ "OutputArtifacts": Array [
+ Object {
+ "Name": "c8d064061d1c8680a574cd5a9f9c9c69b475d41907_Source",
+ },
+ ],
+ "RoleArn": Object {
+ "Fn::GetAtt": Array [
+ "pipelinesPipelineSourceCodeCommitCodePipelineActionRoleF943FC72",
+ "Arn",
+ ],
+ },
+ "RunOrder": 1,
+ },
+ ],
+ "Name": "Source",
+ },
+ Object {
+ "Actions": Array [
+ Object {
+ "ActionTypeId": Object {
+ "Category": "Build",
+ "Owner": "AWS",
+ "Provider": "CodeBuild",
+ "Version": "1",
+ },
+ "Configuration": Object {
+ "EnvironmentVariables": "[{\\"name\\":\\"_PROJECT_CONFIG_HASH\\",\\"type\\":\\"PLAINTEXT\\",\\"value\\":\\"9469ae51f04167eba9cd5c396c8cb8f88d45ac5945a4d807ad180024e03b7a84\\"}]",
+ "ProjectName": Object {
+ "Ref": "pipelinesPipelineBuildsynthCdkBuildProjectC3D1D808",
+ },
+ },
+ "InputArtifacts": Array [
+ Object {
+ "Name": "c8d064061d1c8680a574cd5a9f9c9c69b475d41907_Source",
+ },
+ ],
+ "Name": "synth",
+ "OutputArtifacts": Array [
+ Object {
+ "Name": "synth_Output",
+ },
+ ],
+ "RoleArn": Object {
+ "Fn::GetAtt": Array [
+ "pipelinesCodeBuildActionRole0A34FFD8",
+ "Arn",
+ ],
+ },
+ "RunOrder": 1,
+ },
+ ],
+ "Name": "Build",
+ },
+ Object {
+ "Actions": Array [
+ Object {
+ "ActionTypeId": Object {
+ "Category": "Build",
+ "Owner": "AWS",
+ "Provider": "CodeBuild",
+ "Version": "1",
+ },
+ "Configuration": Object {
+ "EnvironmentVariables": "[{\\"name\\":\\"_PROJECT_CONFIG_HASH\\",\\"type\\":\\"PLAINTEXT\\",\\"value\\":\\"f5c136b42f09ed582b9273672c6585264fb7142640d362897bd6649d732584c2\\"}]",
+ "ProjectName": Object {
+ "Ref": "pipelinesUpdatePipelineSelfMutationFA94E664",
+ },
+ },
+ "InputArtifacts": Array [
+ Object {
+ "Name": "synth_Output",
+ },
+ ],
+ "Name": "SelfMutate",
+ "RoleArn": Object {
+ "Fn::GetAtt": Array [
+ "pipelinesCodeBuildActionRole0A34FFD8",
+ "Arn",
+ ],
+ },
+ "RunOrder": 1,
+ },
+ ],
+ "Name": "UpdatePipeline",
+ },
+ Object {
+ "Actions": Array [
+ Object {
+ "ActionTypeId": Object {
+ "Category": "Invoke",
+ "Owner": "AWS",
+ "Provider": "Lambda",
+ "Version": "1",
+ },
+ "Configuration": Object {
+ "FunctionName": Object {
+ "Ref": "ImageCopyImageCopyHandlerFBE2CA9D",
+ },
+ "UserParameters": Object {
+ "Fn::Join": Array [
+ "",
+ Array [
+ "{\\"SrcImage\\":\\"docker://",
+ Object {
+ "Fn::Select": Array [
+ 4,
+ Object {
+ "Fn::Split": Array [
+ ":",
+ Object {
+ "Fn::GetAtt": Array [
+ "NginxRepo42B51311",
+ "Arn",
+ ],
+ },
+ ],
+ },
+ ],
+ },
+ ".dkr.ecr.",
+ Object {
+ "Fn::Select": Array [
+ 3,
+ Object {
+ "Fn::Split": Array [
+ ":",
+ Object {
+ "Fn::GetAtt": Array [
+ "NginxRepo42B51311",
+ "Arn",
+ ],
+ },
+ ],
+ },
+ ],
+ },
+ ".",
+ Object {
+ "Ref": "AWS::URLSuffix",
+ },
+ "/",
+ Object {
+ "Ref": "NginxRepo42B51311",
+ },
+ ":stable\\",\\"DestImage\\":\\"docker://",
+ Object {
+ "Fn::Select": Array [
+ 4,
+ Object {
+ "Fn::Split": Array [
+ ":",
+ Object {
+ "Fn::GetAtt": Array [
+ "NginxRepo42B51311",
+ "Arn",
+ ],
+ },
+ ],
+ },
+ ],
+ },
+ ".dkr.ecr.",
+ Object {
+ "Fn::Select": Array [
+ 3,
+ Object {
+ "Fn::Split": Array [
+ ":",
+ Object {
+ "Fn::GetAtt": Array [
+ "NginxRepo42B51311",
+ "Arn",
+ ],
+ },
+ ],
+ },
+ ],
+ },
+ ".",
+ Object {
+ "Ref": "AWS::URLSuffix",
+ },
+ "/",
+ Object {
+ "Ref": "NginxRepo42B51311",
+ },
+ ":latest\\"}",
+ ],
+ ],
+ },
+ },
+ "Name": "ImageCopy",
+ "RoleArn": Object {
+ "Fn::GetAtt": Array [
+ "pipelinesPipelineCopyImageImageCopyCodePipelineActionRoleBCA09BEC",
+ "Arn",
+ ],
+ },
+ "RunOrder": 1,
+ },
+ ],
+ "Name": "CopyImage",
+ },
+ ],
+ },
+ "Type": "AWS::CodePipeline::Pipeline",
+ },
+ "pipelinesPipelineEventsRoleDefaultPolicy9E5668AB": Object {
+ "Properties": Object {
+ "PolicyDocument": Object {
+ "Statement": Array [
+ Object {
+ "Action": "codepipeline:StartPipelineExecution",
+ "Effect": "Allow",
+ "Resource": Object {
+ "Fn::Join": Array [
+ "",
+ Array [
+ "arn:",
+ Object {
+ "Ref": "AWS::Partition",
+ },
+ ":codepipeline:",
+ Object {
+ "Ref": "AWS::Region",
+ },
+ ":",
+ Object {
+ "Ref": "AWS::AccountId",
+ },
+ ":",
+ Object {
+ "Ref": "pipelinesPipelineEAE3F1AF",
+ },
+ ],
+ ],
+ },
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "PolicyName": "pipelinesPipelineEventsRoleDefaultPolicy9E5668AB",
+ "Roles": Array [
+ Object {
+ "Ref": "pipelinesPipelineEventsRoleF14AE9B6",
+ },
+ ],
+ },
+ "Type": "AWS::IAM::Policy",
+ },
+ "pipelinesPipelineEventsRoleF14AE9B6": Object {
+ "Properties": Object {
+ "AssumeRolePolicyDocument": Object {
+ "Statement": Array [
+ Object {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Principal": Object {
+ "Service": "events.amazonaws.com",
+ },
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ },
+ "Type": "AWS::IAM::Role",
+ },
+ "pipelinesPipelineRole3396D699": Object {
+ "Properties": Object {
+ "AssumeRolePolicyDocument": Object {
+ "Statement": Array [
+ Object {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Principal": Object {
+ "Service": "codepipeline.amazonaws.com",
+ },
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ },
+ "Type": "AWS::IAM::Role",
+ },
+ "pipelinesPipelineRoleDefaultPolicy8A18F220": Object {
+ "Properties": Object {
+ "PolicyDocument": Object {
+ "Statement": Array [
+ Object {
+ "Action": Array [
+ "s3:GetObject*",
+ "s3:GetBucket*",
+ "s3:List*",
+ "s3:DeleteObject*",
+ "s3:PutObject",
+ "s3:PutObjectLegalHold",
+ "s3:PutObjectRetention",
+ "s3:PutObjectTagging",
+ "s3:PutObjectVersionTagging",
+ "s3:Abort*",
+ ],
+ "Effect": "Allow",
+ "Resource": Array [
+ Object {
+ "Fn::GetAtt": Array [
+ "pipelinesPipelineArtifactsBucket27498DB8",
+ "Arn",
+ ],
+ },
+ Object {
+ "Fn::Join": Array [
+ "",
+ Array [
+ Object {
+ "Fn::GetAtt": Array [
+ "pipelinesPipelineArtifactsBucket27498DB8",
+ "Arn",
+ ],
+ },
+ "/*",
+ ],
+ ],
+ },
+ ],
+ },
+ Object {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Resource": Object {
+ "Fn::GetAtt": Array [
+ "pipelinesPipelineSourceCodeCommitCodePipelineActionRoleF943FC72",
+ "Arn",
+ ],
+ },
+ },
+ Object {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Resource": Object {
+ "Fn::GetAtt": Array [
+ "pipelinesCodeBuildActionRole0A34FFD8",
+ "Arn",
+ ],
+ },
+ },
+ Object {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Resource": Object {
+ "Fn::GetAtt": Array [
+ "pipelinesPipelineCopyImageImageCopyCodePipelineActionRoleBCA09BEC",
+ "Arn",
+ ],
+ },
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "PolicyName": "pipelinesPipelineRoleDefaultPolicy8A18F220",
+ "Roles": Array [
+ Object {
+ "Ref": "pipelinesPipelineRole3396D699",
+ },
+ ],
+ },
+ "Type": "AWS::IAM::Policy",
+ },
+ "pipelinesPipelineSourceCodeCommitCodePipelineActionRoleDefaultPolicy3A67ACE9": Object {
+ "Properties": Object {
+ "PolicyDocument": Object {
+ "Statement": Array [
+ Object {
+ "Action": Array [
+ "s3:GetObject*",
+ "s3:GetBucket*",
+ "s3:List*",
+ "s3:DeleteObject*",
+ "s3:PutObject",
+ "s3:PutObjectLegalHold",
+ "s3:PutObjectRetention",
+ "s3:PutObjectTagging",
+ "s3:PutObjectVersionTagging",
+ "s3:Abort*",
+ ],
+ "Effect": "Allow",
+ "Resource": Array [
+ Object {
+ "Fn::GetAtt": Array [
+ "pipelinesPipelineArtifactsBucket27498DB8",
+ "Arn",
+ ],
+ },
+ Object {
+ "Fn::Join": Array [
+ "",
+ Array [
+ Object {
+ "Fn::GetAtt": Array [
+ "pipelinesPipelineArtifactsBucket27498DB8",
+ "Arn",
+ ],
+ },
+ "/*",
+ ],
+ ],
+ },
+ ],
+ },
+ Object {
+ "Action": Array [
+ "codecommit:GetBranch",
+ "codecommit:GetCommit",
+ "codecommit:UploadArchive",
+ "codecommit:GetUploadArchiveStatus",
+ "codecommit:CancelUploadArchive",
+ ],
+ "Effect": "Allow",
+ "Resource": Object {
+ "Fn::GetAtt": Array [
+ "Repo02AC86CF",
+ "Arn",
+ ],
+ },
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "PolicyName": "pipelinesPipelineSourceCodeCommitCodePipelineActionRoleDefaultPolicy3A67ACE9",
+ "Roles": Array [
+ Object {
+ "Ref": "pipelinesPipelineSourceCodeCommitCodePipelineActionRoleF943FC72",
+ },
+ ],
+ },
+ "Type": "AWS::IAM::Policy",
+ },
+ "pipelinesPipelineSourceCodeCommitCodePipelineActionRoleF943FC72": Object {
+ "Properties": Object {
+ "AssumeRolePolicyDocument": Object {
+ "Statement": Array [
+ Object {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Principal": Object {
+ "AWS": Object {
+ "Fn::Join": Array [
+ "",
+ Array [
+ "arn:",
+ Object {
+ "Ref": "AWS::Partition",
+ },
+ ":iam::",
+ Object {
+ "Ref": "AWS::AccountId",
+ },
+ ":root",
+ ],
+ ],
+ },
+ },
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ },
+ "Type": "AWS::IAM::Role",
+ },
+ "pipelinesUpdatePipelineSelfMutationFA94E664": Object {
+ "Properties": Object {
+ "Artifacts": Object {
+ "Type": "CODEPIPELINE",
+ },
+ "Cache": Object {
+ "Type": "NO_CACHE",
+ },
+ "Description": "Pipeline step Default/Pipeline/UpdatePipeline/SelfMutate",
+ "EncryptionKey": "alias/aws/s3",
+ "Environment": Object {
+ "ComputeType": "BUILD_GENERAL1_SMALL",
+ "Image": "aws/codebuild/standard:7.0",
+ "ImagePullCredentialsType": "CODEBUILD",
+ "PrivilegedMode": false,
+ "Type": "LINUX_CONTAINER",
+ },
+ "ServiceRole": Object {
+ "Fn::GetAtt": Array [
+ "pipelinesUpdatePipelineSelfMutationRole6B594EB5",
+ "Arn",
+ ],
+ },
+ "Source": Object {
+ "BuildSpec": "{
+ \\"version\\": \\"0.2\\",
+ \\"phases\\": {
+ \\"install\\": {
+ \\"commands\\": [
+ \\"npm install -g aws-cdk@2\\"
+ ]
+ },
+ \\"build\\": {
+ \\"commands\\": [
+ \\"cdk -a . deploy Default --require-approval=never --verbose\\"
+ ]
+ }
+ }
+}",
+ "Type": "CODEPIPELINE",
+ },
+ },
+ "Type": "AWS::CodeBuild::Project",
+ },
+ "pipelinesUpdatePipelineSelfMutationRole6B594EB5": Object {
+ "Properties": Object {
+ "AssumeRolePolicyDocument": Object {
+ "Statement": Array [
+ Object {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Principal": Object {
+ "Service": "codebuild.amazonaws.com",
+ },
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ },
+ "Type": "AWS::IAM::Role",
+ },
+ "pipelinesUpdatePipelineSelfMutationRoleDefaultPolicyD785AFC1": Object {
+ "Properties": Object {
+ "PolicyDocument": Object {
+ "Statement": Array [
+ Object {
+ "Action": Array [
+ "logs:CreateLogGroup",
+ "logs:CreateLogStream",
+ "logs:PutLogEvents",
+ ],
+ "Effect": "Allow",
+ "Resource": Array [
+ Object {
+ "Fn::Join": Array [
+ "",
+ Array [
+ "arn:",
+ Object {
+ "Ref": "AWS::Partition",
+ },
+ ":logs:",
+ Object {
+ "Ref": "AWS::Region",
+ },
+ ":",
+ Object {
+ "Ref": "AWS::AccountId",
+ },
+ ":log-group:/aws/codebuild/",
+ Object {
+ "Ref": "pipelinesUpdatePipelineSelfMutationFA94E664",
+ },
+ ],
+ ],
+ },
+ Object {
+ "Fn::Join": Array [
+ "",
+ Array [
+ "arn:",
+ Object {
+ "Ref": "AWS::Partition",
+ },
+ ":logs:",
+ Object {
+ "Ref": "AWS::Region",
+ },
+ ":",
+ Object {
+ "Ref": "AWS::AccountId",
+ },
+ ":log-group:/aws/codebuild/",
+ Object {
+ "Ref": "pipelinesUpdatePipelineSelfMutationFA94E664",
+ },
+ ":*",
+ ],
+ ],
+ },
+ ],
+ },
+ Object {
+ "Action": Array [
+ "codebuild:CreateReportGroup",
+ "codebuild:CreateReport",
+ "codebuild:UpdateReport",
+ "codebuild:BatchPutTestCases",
+ "codebuild:BatchPutCodeCoverages",
+ ],
+ "Effect": "Allow",
+ "Resource": Object {
+ "Fn::Join": Array [
+ "",
+ Array [
+ "arn:",
+ Object {
+ "Ref": "AWS::Partition",
+ },
+ ":codebuild:",
+ Object {
+ "Ref": "AWS::Region",
+ },
+ ":",
+ Object {
+ "Ref": "AWS::AccountId",
+ },
+ ":report-group/",
+ Object {
+ "Ref": "pipelinesUpdatePipelineSelfMutationFA94E664",
+ },
+ "-*",
+ ],
+ ],
+ },
+ },
+ Object {
+ "Action": "sts:AssumeRole",
+ "Condition": Object {
+ "ForAnyValue:StringEquals": Object {
+ "iam:ResourceTag/aws-cdk:bootstrap-role": Array [
+ "image-publishing",
+ "file-publishing",
+ "deploy",
+ ],
+ },
+ },
+ "Effect": "Allow",
+ "Resource": Object {
+ "Fn::Join": Array [
+ "",
+ Array [
+ "arn:*:iam::",
+ Object {
+ "Ref": "AWS::AccountId",
+ },
+ ":role/*",
+ ],
+ ],
+ },
+ },
+ Object {
+ "Action": "cloudformation:DescribeStacks",
+ "Effect": "Allow",
+ "Resource": "*",
+ },
+ Object {
+ "Action": "s3:ListBucket",
+ "Effect": "Allow",
+ "Resource": "*",
+ },
+ Object {
+ "Action": Array [
+ "s3:GetObject*",
+ "s3:GetBucket*",
+ "s3:List*",
+ ],
+ "Effect": "Allow",
+ "Resource": Array [
+ Object {
+ "Fn::GetAtt": Array [
+ "pipelinesPipelineArtifactsBucket27498DB8",
+ "Arn",
+ ],
+ },
+ Object {
+ "Fn::Join": Array [
+ "",
+ Array [
+ Object {
+ "Fn::GetAtt": Array [
+ "pipelinesPipelineArtifactsBucket27498DB8",
+ "Arn",
+ ],
+ },
+ "/*",
+ ],
+ ],
+ },
+ ],
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "PolicyName": "pipelinesUpdatePipelineSelfMutationRoleDefaultPolicyD785AFC1",
+ "Roles": Array [
+ Object {
+ "Ref": "pipelinesUpdatePipelineSelfMutationRole6B594EB5",
+ },
+ ],
+ },
+ "Type": "AWS::IAM::Policy",
+ },
+ },
+ "Rules": Object {
+ "CheckBootstrapVersion": Object {
+ "Assertions": Array [
+ Object {
+ "Assert": Object {
+ "Fn::Not": Array [
+ Object {
+ "Fn::Contains": Array [
+ Array [
+ "1",
+ "2",
+ "3",
+ "4",
+ "5",
+ ],
+ Object {
+ "Ref": "BootstrapVersion",
+ },
+ ],
+ },
+ ],
+ },
+ "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI.",
+ },
+ ],
+ },
+ },
+}
+`;
diff --git a/test/index.test.ts b/test/index.test.ts
index 425ad4b6..25438b4c 100644
--- a/test/index.test.ts
+++ b/test/index.test.ts
@@ -2,7 +2,17 @@
// SPDX-License-Identifier: Apache-2.0
-import { DockerImageName, S3ArchiveName } from '../src';
+import {
+ Stack,
+ RemovalPolicy,
+ aws_codepipeline as codepipeline,
+ aws_ecr as ecr,
+ aws_codepipeline_actions as codepipeline_actions,
+ aws_codecommit as codecommit,
+ pipelines,
+} from 'aws-cdk-lib';
+import { Template } from 'aws-cdk-lib/assertions';
+import { DockerImageName, ECRDeploymentStep, S3ArchiveName } from '../src';
test(`${DockerImageName.name}`, () => {
const name = new DockerImageName('nginx:latest');
@@ -14,4 +24,78 @@ test(`${S3ArchiveName.name}`, () => {
const name = new S3ArchiveName('bucket/nginx.tar', 'nginx:latest');
expect(name.uri).toBe('s3://bucket/nginx.tar:nginx:latest');
+});
+
+describe('lambda in codepipeline', () => {
+ const stack = new Stack();
+ const pipeline = new codepipeline.Pipeline(stack, 'PipelineWithLambda', {});
+
+ const output = new codepipeline.Artifact();
+ const repository = new codecommit.Repository(stack, 'Repo', {
+ repositoryName: 'test-repo',
+ });
+ pipeline.addStage({
+ stageName: 'Source',
+ actions: [
+ new codepipeline_actions.CodeCommitSourceAction({
+ actionName: 'Source',
+ output,
+ repository,
+ }),
+ ],
+ });
+ const stage = pipeline.addStage({
+ stageName: 'CopyImage',
+ });
+
+ const repo = new ecr.Repository(stack, 'NginxRepo', {
+ repositoryName: 'nginx',
+ removalPolicy: RemovalPolicy.DESTROY,
+ });
+
+ new ECRDeploymentStep(stack, 'ImageCopy', {
+ dest: new DockerImageName(`${repo.repositoryUri}:latest`),
+ src: new DockerImageName(`${repo.repositoryUri}:stable`),
+ stage,
+ });
+ const template = Template.fromStack(stack);
+
+ test('matches snapshot', () => {
+ expect(template).toMatchSnapshot();
+ });
+});
+
+describe('lambda in pipelines pipeline', () => {
+ const stack = new Stack();
+ const repository = new codecommit.Repository(stack, 'Repo', {
+ repositoryName: 'test-repo',
+ });
+
+ const pipeline = new pipelines.CodePipeline(stack, 'pipelines', {
+ synth: new pipelines.ShellStep('synth', {
+ input: pipelines.CodePipelineSource.codeCommit(repository, 'master'),
+ commands: [
+ 'mkdir cdk.out',
+ 'touch cdk.out/test',
+ ],
+ }),
+ });
+
+ const wave = pipeline.addWave('CopyImage');
+
+ const repo = new ecr.Repository(stack, 'NginxRepo', {
+ repositoryName: 'nginx',
+ removalPolicy: RemovalPolicy.DESTROY,
+ });
+
+ new ECRDeploymentStep(stack, 'ImageCopy', {
+ dest: new DockerImageName(`${repo.repositoryUri}:latest`),
+ src: new DockerImageName(`${repo.repositoryUri}:stable`),
+ wave,
+ });
+ const template = Template.fromStack(stack);
+
+ test('matches snapshot', () => {
+ expect(template).toMatchSnapshot();
+ });
});
\ No newline at end of file