Skip to content

Commit

Permalink
Check image pushability based on image/tag count limits prior to push
Browse files Browse the repository at this point in the history
  • Loading branch information
abhay-krishna committed Nov 11, 2024
1 parent 1b59c4b commit d2b4e8a
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 1 deletion.
59 changes: 59 additions & 0 deletions release/cli/pkg/aws/ecrpublic/ecrpublic.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,65 @@ func GetAuthConfig(ecrPublicClient *ecrpublic.ECRPublic) (*docker.AuthConfigurat
return authConfig, nil
}

func GetAllImagesCount(imageRepository string, ecrPublicClient *ecrpublic.ECRPublic) (int, error) {
allImages := []*ecrpublic.ImageDetail{}

describeImagesOutput, err := ecrPublicClient.DescribeImages(
&ecrpublic.DescribeImagesInput{
RepositoryName: aws.String(imageRepository),
MaxResults: aws.Int64(1000),
},
)
if err != nil {
return 0, errors.Cause(err)
}
allImages = append(allImages, describeImagesOutput.ImageDetails...)
nextToken := describeImagesOutput.NextToken

for nextToken != nil {
describeImagesOutput, err = ecrPublicClient.DescribeImages(
&ecrpublic.DescribeImagesInput{
RepositoryName: aws.String(imageRepository),
MaxResults: aws.Int64(1000),
NextToken: nextToken,
},
)
if err != nil {
return 0, errors.Cause(err)
}
allImages = append(allImages, describeImagesOutput.ImageDetails...)
nextToken = describeImagesOutput.NextToken
}

return len(allImages), nil
}

func GetTagsCountForImage(imageRepository, imageDigest string, ecrPublicClient *ecrpublic.ECRPublic) (int, error) {
describeImagesOutput, err := ecrPublicClient.DescribeImages(
&ecrpublic.DescribeImagesInput{
RepositoryName: aws.String(imageRepository),
ImageIds: []*ecrpublic.ImageIdentifier{
{
ImageDigest: aws.String(imageDigest),
},
},
},
)
if err != nil {
if strings.Contains(err.Error(), ecrpublic.ErrCodeImageNotFoundException) {
return 0, nil
} else {
return 0, errors.Cause(err)
}
}

if len(describeImagesOutput.ImageDetails) == 0 {
return 0, nil
}

return len(describeImagesOutput.ImageDetails[0].ImageTags), nil
}

func CheckImageExistence(imageUri, imageContainerRegistry string, ecrPublicClient *ecrpublic.ECRPublic) (bool, error) {
repository, tag := artifactutils.SplitImageUri(imageUri, imageContainerRegistry)
_, err := ecrPublicClient.DescribeImages(
Expand Down
3 changes: 3 additions & 0 deletions release/cli/pkg/constants/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,7 @@ const (
//
// (January 2, 15:04:05, 2006, in time zone seven hours west of GMT).
YYYYMMDD = "2006-01-02"

MAX_IMAGES_PER_REPOSITORY = 10000
MAX_TAGS_PER_IMAGE = 1000
)
31 changes: 31 additions & 0 deletions release/cli/pkg/images/images.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
"strings"
"time"

ecrsdk "github.com/aws/aws-sdk-go/service/ecr"
ecrpublicsdk "github.com/aws/aws-sdk-go/service/ecrpublic"
docker "github.com/fsouza/go-dockerclient"
"github.com/pkg/errors"
Expand All @@ -35,6 +36,7 @@ import (
"github.com/aws/eks-anywhere/release/cli/pkg/aws/ecr"
"github.com/aws/eks-anywhere/release/cli/pkg/aws/ecrpublic"
"github.com/aws/eks-anywhere/release/cli/pkg/aws/s3"
"github.com/aws/eks-anywhere/release/cli/pkg/constants"
"github.com/aws/eks-anywhere/release/cli/pkg/filereader"
"github.com/aws/eks-anywhere/release/cli/pkg/retrier"
releasetypes "github.com/aws/eks-anywhere/release/cli/pkg/types"
Expand Down Expand Up @@ -385,3 +387,32 @@ func ComputeImageDigestFromManifest(ecrPublicClient *ecrpublicsdk.ECRPublic, reg

return fmt.Sprintf("%x", digest), nil
}

func CheckRepositoryImagesAndTagsCountLimit(sourceImageUri, releaseImageUri, sourceContainerRegistry, releaseContainerRegistry string, ecrClient *ecrsdk.ECR, ecrPublicClient *ecrpublicsdk.ECRPublic) error {
repository, _ := artifactutils.SplitImageUri(releaseImageUri, releaseContainerRegistry)

fmt.Printf("Checking if image %s can be pushed to repository %s\n", releaseImageUri, repository)

sourceImageDigest, err := ecr.GetImageDigest(sourceImageUri, sourceContainerRegistry, ecrClient)
if err != nil {
return errors.Cause(err)
}

allImagesCount, err := ecrpublic.GetAllImagesCount(repository, ecrPublicClient)
if err != nil {
return errors.Cause(err)
}
if allImagesCount > constants.MAX_IMAGES_PER_REPOSITORY {
return fmt.Errorf("cannot push image [%s] since the repository %s already has the maximum allowed number of images which is '%d'", releaseImageUri, repository, constants.MAX_IMAGES_PER_REPOSITORY)
}

tagsForImageCount, err := ecrpublic.GetTagsCountForImage(repository, sourceImageDigest, ecrPublicClient)
if err != nil {
return errors.Cause(err)
}
if tagsForImageCount > constants.MAX_TAGS_PER_IMAGE {
return fmt.Errorf("cannot push image [%s] since the image with digest [%s] in repository %s already has the maximum allowed number of tags per image which is '%d'", releaseImageUri, sourceImageDigest, repository, constants.MAX_TAGS_PER_IMAGE)
}

return nil
}
14 changes: 13 additions & 1 deletion release/cli/pkg/operations/upload.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,12 +162,24 @@ func handleImageUpload(_ context.Context, r *releasetypes.ReleaseConfig, package
sourceImageUri := artifact.Image.SourceImageURI
releaseImageUri := artifact.Image.ReleaseImageURI
sourceEcrAuthConfig := defaultSourceEcrAuthConfig
sourceContainerRegistry := r.SourceContainerRegistry
sourceEcrClient := r.SourceClients.ECR.EcrClient
if packagesutils.NeedsPackagesAccountArtifacts(r) && (strings.Contains(sourceImageUri, "eks-anywhere-packages") || strings.Contains(sourceImageUri, "ecr-token-refresher") || strings.Contains(sourceImageUri, "credential-provider-package")) {
sourceEcrAuthConfig = packagesSourceEcrAuthConfig
sourceContainerRegistry = r.PackagesSourceContainerRegistry
sourceEcrClient = r.SourceClients.Packages.EcrClient
}
releaseContainerRegistry := r.ReleaseContainerRegistry
releaseEcrPublicClient := r.ReleaseClients.ECRPublic.Client
fmt.Printf("Source Image - %s\n", sourceImageUri)
fmt.Printf("Destination Image - %s\n", releaseImageUri)
err := images.CopyToDestination(sourceEcrAuthConfig, releaseEcrAuthConfig, sourceImageUri, releaseImageUri)

err := images.CheckRepositoryImagesAndTagsCountLimit(sourceImageUri, releaseImageUri, sourceContainerRegistry, releaseContainerRegistry, sourceEcrClient, releaseEcrPublicClient)
if err != nil {
return fmt.Errorf("checking pushability of image [%s] based on destination repository images or tags limits: %v", releaseImageUri, err)
}

err = images.CopyToDestination(sourceEcrAuthConfig, releaseEcrAuthConfig, sourceImageUri, releaseImageUri)
if err != nil {
return fmt.Errorf("copying image from source [%s] to destination [%s]: %v", sourceImageUri, releaseImageUri, err)
}
Expand Down

0 comments on commit d2b4e8a

Please sign in to comment.