Pārlūkot izejas kodu

Merge branch 'master' into nafees/api-v1

Mohammed Nafees 3 gadi atpakaļ
vecāks
revīzija
a17235ea68

+ 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

@@ -405,11 +405,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

@@ -195,9 +195,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
@@ -205,9 +205,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"`
 }

+ 96 - 30
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"
@@ -701,30 +702,78 @@ func (r *Registry) GetECRPaginatedImages(
 		return []*ptypes.Image{}, nil, nil
 	}
 
-	describeResp, err := svc.DescribeImages(&ecr.DescribeImagesInput{
-		RepositoryName: &repoName,
-		ImageIds:       resp.ImageIds,
-	})
+	imageIDLen := len(resp.ImageIds)
+	imageDetails := make([]*ecr.ImageDetail, 0)
+	imageIDMap := make(map[string]bool)
 
-	if err != nil {
-		return nil, nil, err
+	for _, id := range resp.ImageIds {
+		imageIDMap[*id.ImageTag] = true
 	}
 
-	imageDetails := describeResp.ImageDetails
+	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 {
+		end := start + 100
+		if end > imageIDLen {
+			end = imageIDLen
+		}
+
+		wg.Add(1)
+
+		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
+			}
+
+			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)
+	}
+
 	return res, resp.NextToken, nil
 }
 
@@ -782,46 +831,63 @@ func (r *Registry) listECRImages(repoName string, repo repository.Repository) ([
 		nextToken = resp.NextToken
 	}
 
-	describeResp, err := svc.DescribeImages(&ecr.DescribeImagesInput{
-		RepositoryName: &repoName,
-		ImageIds:       imageIDs,
-	})
+	imageIDLen := len(imageIDs)
+	imageDetails := make([]*ecr.ImageDetail, 0)
 
-	if err != nil {
-		return nil, err
-	}
+	var wg sync.WaitGroup
+	var mu sync.Mutex
 
-	imageDetails := describeResp.ImageDetails
+	// AWS API expects the length of imageIDs to be at max 100 at a time
+	for start := 0; start < imageIDLen; start += 100 {
+		end := start + 100
+		if end > imageIDLen {
+			end = imageIDLen
+		}
 
-	nextToken = describeResp.NextToken
+		wg.Add(1)
 
-	for nextToken != nil {
-		describeResp, err := svc.DescribeImages(&ecr.DescribeImagesInput{
-			RepositoryName: &repoName,
-			NextToken:      nextToken,
-		})
+		go func(start, end int) {
+			defer wg.Done()
 
-		if err != nil {
-			return nil, err
-		}
+			describeResp, err := svc.DescribeImages(&ecr.DescribeImagesInput{
+				RepositoryName: &repoName,
+				ImageIds:       imageIDs[start:end],
+			})
 
-		nextToken = describeResp.NextToken
-		imageDetails = append(imageDetails, describeResp.ImageDetails...)
+			if err != nil {
+				return
+			}
+
+			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 := imageInfoMap[*tag]; !ok {
+				imageInfoMap[*tag] = newImage
+			}
 		}
 	}
 
+	for _, v := range imageInfoMap {
+		res = append(res, v)
+	}
+
 	return res, nil
 }