Parcourir la source

add more gar support

Mohammed Nafees il y a 3 ans
Parent
commit
c7134b99fb
7 fichiers modifiés avec 188 ajouts et 4 suppressions
  1. 1 1
      api/types/registry.go
  2. 26 0
      cli/cmd/connect.go
  3. 92 0
      cli/cmd/connect/gar.go
  4. 2 2
      cli/cmd/connect/gcr.go
  5. 1 0
      go.mod
  6. 2 0
      go.sum
  7. 64 1
      internal/registry/registry.go

+ 1 - 1
api/types/registry.go

@@ -26,7 +26,7 @@ type Registry struct {
 	URL string `json:"url"`
 
 	// The integration service for this registry
-	// enum: gcr,ecr,acr,docr,dockerhub
+	// enum: gcr,gar,ecr,acr,docr,dockerhub
 	// example: ecr
 	Service string `json:"service"`
 

+ 26 - 0
cli/cmd/connect.go

@@ -92,6 +92,18 @@ var connectGCRCmd = &cobra.Command{
 	},
 }
 
+var connectGARCmd = &cobra.Command{
+	Use:   "gar",
+	Short: "Adds a GAR instance to a project",
+	Run: func(cmd *cobra.Command, args []string) {
+		err := checkLoginAndRun(args, runConnectGAR)
+
+		if err != nil {
+			os.Exit(1)
+		}
+	},
+}
+
 var connectDOCRCmd = &cobra.Command{
 	Use:   "docr",
 	Short: "Adds a DOCR instance to a project",
@@ -127,6 +139,7 @@ func init() {
 	connectCmd.AddCommand(connectRegistryCmd)
 	connectCmd.AddCommand(connectDockerhubCmd)
 	connectCmd.AddCommand(connectGCRCmd)
+	connectCmd.AddCommand(connectGARCmd)
 	connectCmd.AddCommand(connectDOCRCmd)
 	connectCmd.AddCommand(connectHelmRepoCmd)
 }
@@ -179,6 +192,19 @@ func runConnectGCR(_ *types.GetAuthenticatedUserResponse, client *api.Client, _
 	return cliConf.SetRegistry(regID)
 }
 
+func runConnectGAR(_ *types.GetAuthenticatedUserResponse, client *api.Client, _ []string) error {
+	regID, err := connect.GAR(
+		client,
+		cliConf.Project,
+	)
+
+	if err != nil {
+		return err
+	}
+
+	return cliConf.SetRegistry(regID)
+}
+
 func runConnectDOCR(_ *types.GetAuthenticatedUserResponse, client *api.Client, _ []string) error {
 	regID, err := connect.DOCR(
 		client,

+ 92 - 0
cli/cmd/connect/gar.go

@@ -0,0 +1,92 @@
+package connect
+
+import (
+	"context"
+	"fmt"
+	"io/ioutil"
+	"os"
+
+	"github.com/fatih/color"
+
+	api "github.com/porter-dev/porter/api/client"
+	"github.com/porter-dev/porter/api/types"
+	"github.com/porter-dev/porter/cli/cmd/utils"
+)
+
+// GAR creates a GAR integration
+func GAR(
+	client *api.Client,
+	projectID uint,
+) (uint, error) {
+	// if project ID is 0, ask the user to set the project ID or create a project
+	if projectID == 0 {
+		return 0, fmt.Errorf("no project set, please run porter config set-project")
+	}
+
+	keyFileLocation, err := utils.PromptPlaintext(fmt.Sprintf(`Please provide the full path to a service account key file.
+Key file location: `))
+
+	if err != nil {
+		return 0, err
+	}
+
+	// attempt to read the key file location
+	if info, err := os.Stat(keyFileLocation); !os.IsNotExist(err) && !info.IsDir() {
+		// read the file
+		bytes, err := ioutil.ReadFile(keyFileLocation)
+
+		if err != nil {
+			return 0, err
+		}
+
+		// create the gcp integration
+		integration, err := client.CreateGCPIntegration(
+			context.Background(),
+			projectID,
+			&types.CreateGCPRequest{
+				GCPKeyData: string(bytes),
+			},
+		)
+
+		if err != nil {
+			return 0, err
+		}
+
+		color.New(color.FgGreen).Printf("created gcp integration with id %d\n", integration.ID)
+
+		region, err := utils.PromptPlaintext(fmt.Sprintf(`Please enter the artifact registry region. For example, us-central-1.
+Artifact registry region: `))
+
+		if err != nil {
+			return 0, err
+		}
+
+		// create the registry
+		// query for registry name
+		regName, err := utils.PromptPlaintext(fmt.Sprintf(`Give this registry a name: `))
+
+		if err != nil {
+			return 0, err
+		}
+
+		reg, err := client.CreateRegistry(
+			context.Background(),
+			projectID,
+			&types.CreateRegistryRequest{
+				Name:             regName,
+				GCPIntegrationID: integration.ID,
+				URL:              region + "-docker.pkg.dev/" + integration.GCPProjectID,
+			},
+		)
+
+		if err != nil {
+			return 0, err
+		}
+
+		color.New(color.FgGreen).Printf("created registry with id %d and name %s\n", reg.ID, reg.Name)
+
+		return reg.ID, nil
+	}
+
+	return 0, fmt.Errorf("could not read service account key file")
+}

+ 2 - 2
cli/cmd/connect/gcr.go

@@ -20,7 +20,7 @@ func GCR(
 ) (uint, error) {
 	// if project ID is 0, ask the user to set the project ID or create a project
 	if projectID == 0 {
-		return 0, fmt.Errorf("no project set, please run porter project set [id]")
+		return 0, fmt.Errorf("no project set, please run porter config set-project")
 	}
 
 	keyFileLocation, err := utils.PromptPlaintext(fmt.Sprintf(`Please provide the full path to a service account key file.
@@ -39,7 +39,7 @@ Key file location: `))
 			return 0, err
 		}
 
-		// create the aws integration
+		// create the gcp integration
 		integration, err := client.CreateGCPIntegration(
 			context.Background(),
 			projectID,

+ 1 - 0
go.mod

@@ -76,6 +76,7 @@ require (
 require (
 	cloud.google.com/go/artifactregistry v1.3.0 // indirect
 	cloud.google.com/go/compute v1.6.1 // indirect
+	cloud.google.com/go/iam v0.3.0 // indirect
 	github.com/Azure/azure-sdk-for-go v65.0.0+incompatible // indirect
 	github.com/Azure/azure-sdk-for-go/sdk/azcore v0.23.1 // indirect
 	github.com/Azure/azure-sdk-for-go/sdk/internal v0.9.1 // indirect

+ 2 - 0
go.sum

@@ -54,6 +54,8 @@ cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1
 cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
 cloud.google.com/go/firestore v1.6.0/go.mod h1:afJwI0vaXwAG54kI7A//lP/lSPDkQORQuMkv56TxEPU=
 cloud.google.com/go/firestore v1.6.1/go.mod h1:asNXNOzBdyVQmEU+ggO8UPodTkEVFW5Qx+rwHnAz+EY=
+cloud.google.com/go/iam v0.3.0 h1:exkAomrVUuzx9kWFI1wm3KI0uoDeUFPB4kKGzx6x+Gc=
+cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY=
 cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
 cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
 cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=

+ 64 - 1
internal/registry/registry.go

@@ -74,7 +74,11 @@ func (r *Registry) ListRepositories(
 	}
 
 	if r.GCPIntegrationID != 0 {
-		return r.listGCRRepositories(repo)
+		if strings.Contains(r.URL, "pkg.dev") {
+			return r.listGARRepositories(repo)
+		} else {
+			return r.listGCRRepositories(repo)
+		}
 	}
 
 	if r.DOIntegrationID != 0 {
@@ -207,6 +211,65 @@ func (r *Registry) listGCRRepositories(
 	return res, nil
 }
 
+func (r *Registry) listGARRepositories(
+	repo repository.Repository,
+) ([]*ptypes.RegistryRepository, error) {
+	gcpInt, err := repo.GCPIntegration().ReadGCPIntegration(
+		r.ProjectID,
+		r.GCPIntegrationID,
+	)
+
+	if err != nil {
+		return nil, err
+	}
+
+	client, err := artifactregistry.NewClient(context.Background(), option.WithCredentialsJSON(gcpInt.GCPKeyData))
+
+	if err != nil {
+		return nil, err
+	}
+
+	var res []*ptypes.RegistryRepository
+	nextToken := ""
+
+	parsedURL, err := url.Parse("https://" + r.URL)
+
+	if err != nil {
+		return nil, err
+	}
+
+	for {
+		it := client.ListRepositories(context.Background(), &artifactregistrypb.ListRepositoriesRequest{
+			Parent:    gcpInt.GCPProjectID,
+			PageSize:  1000,
+			PageToken: nextToken,
+		})
+
+		for {
+			resp, err := it.Next()
+
+			if err == iterator.Done {
+				break
+			} else if err != nil {
+				return nil, err
+			}
+
+			res = append(res, &ptypes.RegistryRepository{
+				Name: resp.GetName(),
+				URI:  parsedURL.Host + "/" + resp.GetName(),
+			})
+		}
+
+		if it.PageInfo().Token == "" {
+			break
+		}
+
+		nextToken = it.PageInfo().Token
+	}
+
+	return res, nil
+}
+
 func (r *Registry) listECRRepositories(repo repository.Repository) ([]*ptypes.RegistryRepository, error) {
 	aws, err := repo.AWSIntegration().ReadAWSIntegration(
 		r.ProjectID,