diff --git a/API.md b/API.md index b5d1470e..aec2b357 100644 --- a/API.md +++ b/API.md @@ -75,6 +75,7 @@ new ECRDeployment(scope: Construct, id: string, props: ECRDeploymentProps) * **props** ([ECRDeploymentProps](#cdk-ecr-deployment-ecrdeploymentprops)) *No description* * **dest** ([IImageName](#cdk-ecr-deployment-iimagename)) The destination of the docker image. * **src** ([IImageName](#cdk-ecr-deployment-iimagename)) The source of the docker image. + * **architecture** (string) The architecture of the docker images to copy. __*Optional*__ * **buildImage** (string) Image to use to build Golang lambda for custom resource, if download fails or is not wanted. __*Default*__: public.ecr.aws/sam/build-go1.x:latest * **environment** (Map) The environment variable to set. __*Optional*__ * **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. __*Default*__: 512 @@ -144,6 +145,7 @@ Name | Type | Description -----|------|------------- **dest** | [IImageName](#cdk-ecr-deployment-iimagename) | The destination of the docker image. **src** | [IImageName](#cdk-ecr-deployment-iimagename) | The source of the docker image. +**architecture**? | string | The architecture of the docker images to copy.
__*Optional*__ **buildImage**? | string | Image to use to build Golang lambda for custom resource, if download fails or is not wanted.
__*Default*__: public.ecr.aws/sam/build-go1.x:latest **environment**? | Map | The environment variable to set.
__*Optional*__ **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.
__*Default*__: 512 diff --git a/lambda/Dockerfile b/lambda/Dockerfile index 1e6c581d..913949d4 100644 --- a/lambda/Dockerfile +++ b/lambda/Dockerfile @@ -18,9 +18,9 @@ COPY go.mod go.sum ./ RUN go env -# RUN go mod download -x - COPY . /ws RUN mkdir -p /asset/ && \ make OUTPUT=/asset/bootstrap + +ENTRYPOINT [ "/asset/bootstrap" ] \ No newline at end of file diff --git a/lambda/main.go b/lambda/main.go index 639d52c6..a9fe646b 100644 --- a/lambda/main.go +++ b/lambda/main.go @@ -71,7 +71,12 @@ func handler(ctx context.Context, event cfn.Event) (physicalResourceID string, d return physicalResourceID, data, err } - log.Printf("SrcImage: %v DestImage: %v", srcImage, destImage) + arch, err := getStrPropsDefault(event.ResourceProperties, ARCHITECTURE, "") + if err != nil { + return physicalResourceID, data, err + } + + log.Printf("SrcImage: %v DestImage: %v Architecture: %v", srcImage, destImage, arch) srcRef, err := alltransports.ParseImageName(srcImage) if err != nil { @@ -82,13 +87,13 @@ func handler(ctx context.Context, event cfn.Event) (physicalResourceID string, d return physicalResourceID, data, err } - srcOpts := NewImageOpts(srcImage) + srcOpts := NewImageOpts(srcImage, arch) srcOpts.SetCreds(srcCreds) srcCtx, err := srcOpts.NewSystemContext() if err != nil { return physicalResourceID, data, err } - destOpts := NewImageOpts(destImage) + destOpts := NewImageOpts(destImage, arch) destOpts.SetCreds(destCreds) destCtx, err := destOpts.NewSystemContext() if err != nil { diff --git a/lambda/main_test.go b/lambda/main_test.go index a28b323f..036f4bc6 100644 --- a/lambda/main_test.go +++ b/lambda/main_test.go @@ -33,10 +33,10 @@ func TestMain(t *testing.T) { destRef, err := alltransports.ParseImageName(destImage) assert.NoError(t, err) - srcOpts := NewImageOpts(srcImage) + srcOpts := NewImageOpts(srcImage, "arm64") srcCtx, err := srcOpts.NewSystemContext() assert.NoError(t, err) - destOpts := NewImageOpts(destImage) + destOpts := NewImageOpts(destImage, "arm64") destCtx, err := destOpts.NewSystemContext() assert.NoError(t, err) diff --git a/lambda/utils.go b/lambda/utils.go index 461c3807..6cc51f27 100644 --- a/lambda/utils.go +++ b/lambda/utils.go @@ -21,10 +21,11 @@ import ( ) const ( - SRC_IMAGE string = "SrcImage" - DEST_IMAGE string = "DestImage" - SRC_CREDS string = "SrcCreds" - DEST_CREDS string = "DestCreds" + SRC_IMAGE string = "SrcImage" + DEST_IMAGE string = "DestImage" + SRC_CREDS string = "SrcCreds" + DEST_CREDS string = "DestCreds" + ARCHITECTURE string = "Architecture" ) type ECRAuth struct { @@ -35,6 +36,33 @@ type ECRAuth struct { ExpiresAt time.Time } +var validArchs = []string{ + "386", + "amd64", + "amd64p32", + "arm", + "arm64", + "arm64be", + "armbe", + "loong64", + "mips", + "mips64", + "mips64le", + "mips64p32", + "mips64p32le", + "mipsle", + "ppc", + "ppc64", + "ppc64le", + "riscv", + "riscv64", + "s390", + "s390x", + "sparc", + "sparc64", + "wasm", +} + func GetECRRegion(uri string) string { re := regexp.MustCompile(`dkr\.ecr\.(.+?)\.`) m := re.FindStringSubmatch(uri) @@ -86,14 +114,15 @@ type ImageOpts struct { requireECRLogin bool region string creds string + architecture string } -func NewImageOpts(uri string) *ImageOpts { +func NewImageOpts(uri string, arch string) *ImageOpts { requireECRLogin := strings.Contains(uri, "dkr.ecr") if requireECRLogin { - return &ImageOpts{uri, requireECRLogin, GetECRRegion(uri), ""} + return &ImageOpts{uri, requireECRLogin, GetECRRegion(uri), "", arch} } else { - return &ImageOpts{uri, requireECRLogin, "", ""} + return &ImageOpts{uri, requireECRLogin, "", "", arch} } } @@ -109,6 +138,7 @@ func (s *ImageOpts) NewSystemContext() (*types.SystemContext, error) { ctx := &types.SystemContext{ DockerRegistryUserAgent: "ecr-deployment", DockerAuthConfig: &types.DockerAuthConfig{}, + ArchitectureChoice: s.architecture, } if s.creds != "" { @@ -184,3 +214,13 @@ func GetSecret(secretId string) (secret string, err error) { } return *resp.SecretString, nil } + +func IsValidGOARCH(arch string) bool { + for _, validArch := range validArchs { + if arch == validArch { + return true + } + } + + return false +} diff --git a/package.json b/package.json index 809997ce..a21363d0 100644 --- a/package.json +++ b/package.json @@ -90,7 +90,7 @@ ], "main": "lib/index.js", "license": "Apache-2.0", - "version": "0.0.0", + "version": "3.0.0", "jest": { "testMatch": [ "/src/**/__tests__/**/*.ts?(x)", diff --git a/publish-ark-image.sh b/publish-ark-image.sh new file mode 100755 index 00000000..d2afd42d --- /dev/null +++ b/publish-ark-image.sh @@ -0,0 +1,24 @@ +#!/bin/bash + +set -e + +ECR_URI="758920976184.dkr.ecr.us-east-1.amazonaws.com" +ECR_REPO_URI=$ECR_URI/cdk-ecr-deployment +# Authenticate with AWS ECR +aws ecr get-login-password --profile "$AWS_PROFILE" --region "$AWS_REGION" | docker login --username AWS --password-stdin "$ECR_URI" + +# Get the current Git commit hash +GIT_COMMIT_HASH=$(git rev-parse --short HEAD) + +# push to registry +# --provenance=true necessary to avoid the error https://stackoverflow.com/a/75149347/4820648 +docker buildx build \ + --provenance=false \ + --file lambda/Dockerfile \ + --push \ + --tag $ECR_REPO_URI:latest \ + --tag $ECR_REPO_URI:$GIT_COMMIT_HASH \ + --platform linux/amd64 \ + --progress=plain \ + lambda/. + diff --git a/src/index.ts b/src/index.ts index 388ed888..34560afc 100644 --- a/src/index.ts +++ b/src/index.ts @@ -31,6 +31,11 @@ export interface ECRDeploymentProps { */ readonly dest: IImageName; + /** + * The architecture of the docker images to copy. + */ + readonly architecture?: string; + /** * 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. @@ -192,6 +197,7 @@ export class ECRDeployment extends Construct { SrcCreds: props.src.creds, DestImage: props.dest.uri, DestCreds: props.dest.creds, + Architecture: props.architecture, }, }); } diff --git a/test/example.ecr-deployment.ts b/test/example.ecr-deployment.ts index 2d5bd7c8..d7ea87aa 100644 --- a/test/example.ecr-deployment.ts +++ b/test/example.ecr-deployment.ts @@ -32,11 +32,13 @@ class TestECRDeployment extends Stack { new ecrDeploy.ECRDeployment(this, 'DeployECRImage', { src: new ecrDeploy.DockerImageName(image.imageUri), dest: new ecrDeploy.DockerImageName(`${repo.repositoryUri}:latest`), + architecture: 'arm64', }); new ecrDeploy.ECRDeployment(this, 'DeployDockerImage', { src: new ecrDeploy.DockerImageName('javacs3/javacs3:latest', 'dockerhub'), dest: new ecrDeploy.DockerImageName(`${repo.repositoryUri}:dockerhub`), + architecture: 'arm64', }).addToPrincipalPolicy(new iam.PolicyStatement({ effect: iam.Effect.ALLOW, actions: [