فهرست منبع

fix fetching images from ECR

Mohammed Nafees 3 سال پیش
والد
کامیت
80990f3c4b
4فایلهای تغییر یافته به همراه97 افزوده شده و 34 حذف شده
  1. 1 2
      api/server/handlers/v1/registry/list_images.go
  2. 5 3
      api/server/router/v1/registry.go
  3. 6 6
      api/types/registry.go
  4. 85 23
      internal/registry/registry.go

+ 1 - 2
api/server/handlers/v1/registry/list_images.go

@@ -3,7 +3,6 @@ package registry
 import (
 	"fmt"
 	"net/http"
-	"net/url"
 
 	"github.com/porter-dev/porter/api/server/handlers"
 	"github.com/porter-dev/porter/api/server/shared"
@@ -76,7 +75,7 @@ func (c *RegistryListImagesHandler) ServeHTTP(w http.ResponseWriter, r *http.Req
 		}
 
 		if nextToken != nil {
-			res.Next = url.QueryEscape(*nextToken)
+			res.Next = *nextToken
 		}
 
 		res.Images = append(res.Images, imgs...)

+ 5 - 3
api/server/router/v1/registry.go

@@ -400,11 +400,13 @@ func getV1RegistryRoutes(
 	//     in: query
 	//     description: The next page string used for pagination, from a previous request.
 	//     type: string
-	//   - name: next_page
+	//   - name: page
 	//     in: query
-	//     description: The next page number used for pagination, from a previous request.
+	//     description: |
+	//       The page number used for pagination, possibly from a previous request.
+	//       (**DigitalOcean only**)
 	//     type: integer
-	//     minimum: 2
+	//     minimum: 1
 	// responses:
 	//   '200':
 	//     description: Successfully listed images

+ 6 - 6
api/types/registry.go

@@ -193,9 +193,9 @@ type ListRegistryRepositoryResponse []*RegistryRepository
 type ListImageResponse []*Image
 
 type V1ListImageRequest struct {
-	Num      int64  `schema:"num"`
-	Next     string `schema:"next"`
-	NextPage uint   `schema:"next_page"`
+	Num  int64  `schema:"num"`
+	Next string `schema:"next"`
+	Page uint   `schema:"page"`
 }
 
 // swagger:model V1ListImageResponse
@@ -203,9 +203,9 @@ type V1ListImageResponse struct {
 	// The list of repository images with tags
 	Images []*Image `json:"images" form:"required"`
 
-	// The next page number used for pagination, when applicable
-	NextPage uint `json:"num_page,omitempty"`
+	// The next page number used for pagination (**DigitalOcean only**)
+	NextPage uint `json:"next_page,omitempty"`
 
-	// The next page string used for pagination, when application
+	// The next page cursor used for pagination
 	Next string `json:"next,omitempty"`
 }

+ 85 - 23
internal/registry/registry.go

@@ -8,6 +8,7 @@ import (
 	"net/http"
 	"net/url"
 	"strings"
+	"sync"
 	"time"
 
 	"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
@@ -702,7 +703,15 @@ func (r *Registry) GetECRPaginatedImages(
 	}
 
 	imageIDLen := len(resp.ImageIds)
-	imageDetails := make([]*ecr.ImageDetail, imageIDLen)
+	imageDetails := make([]*ecr.ImageDetail, 0)
+	imageIDMap := make(map[string]bool)
+
+	for _, id := range resp.ImageIds {
+		imageIDMap[*id.ImageTag] = true
+	}
+
+	var wg sync.WaitGroup
+	var mu sync.Mutex
 
 	// AWS API expects the length of imageIDs to be at max 100 at a time
 	for start := 0; start < imageIDLen; start += 100 {
@@ -711,31 +720,62 @@ func (r *Registry) GetECRPaginatedImages(
 			end = imageIDLen
 		}
 
-		describeResp, err := svc.DescribeImages(&ecr.DescribeImagesInput{
-			RepositoryName: &repoName,
-			ImageIds:       resp.ImageIds[start:end],
-		})
+		wg.Add(1)
 
-		if err != nil {
-			return nil, nil, err
-		}
+		go func(start, end int) {
+			defer wg.Done()
+
+			describeResp, err := svc.DescribeImages(&ecr.DescribeImagesInput{
+				RepositoryName: &repoName,
+				ImageIds:       resp.ImageIds[start:end],
+			})
+
+			if err != nil {
+				return
+			}
 
-		imageDetails = append(imageDetails, describeResp.ImageDetails...)
+			mu.Lock()
+			imageDetails = append(imageDetails, describeResp.ImageDetails...)
+			mu.Unlock()
+		}(start, end)
 	}
 
+	wg.Wait()
+
 	res := make([]*ptypes.Image, 0)
+	imageInfoMap := make(map[string]*ptypes.Image)
 
 	for _, img := range imageDetails {
 		for _, tag := range img.ImageTags {
-			res = append(res, &ptypes.Image{
+			newImage := &ptypes.Image{
 				Digest:         *img.ImageDigest,
 				Tag:            *tag,
 				RepositoryName: repoName,
 				PushedAt:       img.ImagePushedAt,
-			})
+			}
+
+			if _, ok := imageIDMap[*tag]; ok {
+				if _, ok := imageInfoMap[*tag]; !ok {
+					imageInfoMap[*tag] = newImage
+				}
+			}
+
+			if len(imageInfoMap) == int(maxResults) {
+				break
+			}
+		}
+
+		if len(imageInfoMap) == int(maxResults) {
+			break
 		}
 	}
 
+	for _, v := range imageInfoMap {
+		res = append(res, v)
+	}
+
+	fmt.Printf("LEN: %d\n", len(res))
+
 	return res, resp.NextToken, nil
 }
 
@@ -794,7 +834,10 @@ func (r *Registry) listECRImages(repoName string, repo repository.Repository) ([
 	}
 
 	imageIDLen := len(imageIDs)
-	imageDetails := make([]*ecr.ImageDetail, imageIDLen)
+	imageDetails := make([]*ecr.ImageDetail, 0)
+
+	var wg sync.WaitGroup
+	var mu sync.Mutex
 
 	// AWS API expects the length of imageIDs to be at max 100 at a time
 	for start := 0; start < imageIDLen; start += 100 {
@@ -803,31 +846,50 @@ func (r *Registry) listECRImages(repoName string, repo repository.Repository) ([
 			end = imageIDLen
 		}
 
-		describeResp, err := svc.DescribeImages(&ecr.DescribeImagesInput{
-			RepositoryName: &repoName,
-			ImageIds:       imageIDs[start:end],
-		})
+		wg.Add(1)
 
-		if err != nil {
-			return nil, err
-		}
+		go func(start, end int) {
+			defer wg.Done()
+
+			describeResp, err := svc.DescribeImages(&ecr.DescribeImagesInput{
+				RepositoryName: &repoName,
+				ImageIds:       imageIDs[start:end],
+			})
 
-		imageDetails = append(imageDetails, describeResp.ImageDetails...)
+			if err != nil {
+				return
+			}
+
+			mu.Lock()
+			imageDetails = append(imageDetails, describeResp.ImageDetails...)
+			mu.Unlock()
+		}(start, end)
 	}
 
-	res := make([]*ptypes.Image, len(imageDetails))
+	wg.Wait()
+
+	res := make([]*ptypes.Image, 0)
+	imageInfoMap := make(map[string]*ptypes.Image)
 
 	for _, img := range imageDetails {
 		for _, tag := range img.ImageTags {
-			res = append(res, &ptypes.Image{
+			newImage := &ptypes.Image{
 				Digest:         *img.ImageDigest,
 				Tag:            *tag,
 				RepositoryName: repoName,
 				PushedAt:       img.ImagePushedAt,
-			})
+			}
+
+			if _, ok := imageInfoMap[*tag]; !ok {
+				imageInfoMap[*tag] = newImage
+			}
 		}
 	}
 
+	for _, v := range imageInfoMap {
+		res = append(res, v)
+	}
+
 	return res, nil
 }