Просмотр исходного кода

Merge branch 'beta.2.integration-backend' of https://github.com/porter-dev/porter

jusrhee 5 лет назад
Родитель
Сommit
f6ed35adf7

+ 1 - 4
internal/models/registry.go

@@ -24,10 +24,7 @@ type Registry struct {
 	AWSIntegrationID uint
 
 	// A token cache that can be used by an auth mechanism (integration), if desired
-	IntTokenCache integrations.TokenCache
-
-	// A token cache that can be used by a Docker registry for JWT tokens, if necessary
-	DockerTokenCache integrations.RegTokenCache
+	TokenCache integrations.RegTokenCache
 }
 
 // RegistryExternal is an external Registry to be shared over REST

+ 130 - 46
internal/registry/registry.go

@@ -66,62 +66,77 @@ type gcrRepositoryResp struct {
 func (r *Registry) listGCRRepositories(
 	repo repository.Repository,
 ) ([]*Repository, error) {
-	jwtTok := string(r.DockerTokenCache.Token)
+	// jwtTok := string(r.DockerTokenCache.Token)
 
-	// if a jwt token does not exist or is expired, refresh it
-	if r.DockerTokenCache.IsExpired() || len(jwtTok) == 0 {
-		gcp, err := repo.GCPIntegration.ReadGCPIntegration(
-			r.GCPIntegrationID,
-		)
+	// // if a jwt token does not exist or is expired, refresh it
+	// if r.DockerTokenCache.IsExpired() || len(jwtTok) == 0 {
+	// 	gcp, err := repo.GCPIntegration.ReadGCPIntegration(
+	// 		r.GCPIntegrationID,
+	// 	)
 
-		if err != nil {
-			return nil, err
-		}
+	// 	if err != nil {
+	// 		return nil, err
+	// 	}
 
-		// get oauth2 access token
-		oauthTok, err := gcp.GetBearerToken(r.getTokenCache, r.setTokenCacheFunc(repo))
+	// 	// get oauth2 access token
+	// 	oauthTok, err := gcp.GetBearerToken(r.getTokenCache, r.setTokenCacheFunc(repo))
 
-		if err != nil {
-			return nil, err
-		}
+	// 	if err != nil {
+	// 		return nil, err
+	// 	}
 
-		// get jwt token
-		client := &http.Client{}
+	// 	// get jwt token
+	// 	client := &http.Client{}
 
-		req, err := http.NewRequest(
-			"GET",
-			"https://gcr.io/v2/token?service=gcr.io&scope=registry:catalog:*",
-			nil,
-		)
+	// 	req, err := http.NewRequest(
+	// 		"GET",
+	// 		"https://gcr.io/v2/token?service=gcr.io&scope=registry:catalog:*",
+	// 		nil,
+	// 	)
 
-		req.SetBasicAuth("_token", oauthTok)
+	// 	req.SetBasicAuth("_token", oauthTok)
 
-		resp, err := client.Do(req)
+	// 	resp, err := client.Do(req)
 
-		if err != nil {
-			return nil, err
-		}
+	// 	if err != nil {
+	// 		return nil, err
+	// 	}
 
-		jwtSource := gcrJWT{}
+	// 	jwtSource := gcrJWT{}
 
-		if err := json.NewDecoder(resp.Body).Decode(&jwtSource); err != nil {
-			return nil, fmt.Errorf("Invalid token JSON from metadata: %v", err)
-		}
+	// 	if err := json.NewDecoder(resp.Body).Decode(&jwtSource); err != nil {
+	// 		return nil, fmt.Errorf("Invalid token JSON from metadata: %v", err)
+	// 	}
 
-		_, err = repo.Registry.UpdateRegistryDockerTokenCache(
-			&ints.RegTokenCache{
-				RegistryID: r.ID,
-				Token:      []byte(jwtSource.AccessToken),
-				// subtract some time from expiry for buffer
-				Expiry: time.Now().Add(time.Second*time.Duration(jwtSource.ExpiresInSec) - 5*time.Second),
-			},
-		)
+	// 	_, err = repo.Registry.UpdateRegistryDockerTokenCache(
+	// 		&ints.RegTokenCache{
+	// 			RegistryID: r.ID,
+	// 			Token:      []byte(jwtSource.AccessToken),
+	// 			// subtract some time from expiry for buffer
+	// 			Expiry: time.Now().Add(time.Second*time.Duration(jwtSource.ExpiresInSec) - 5*time.Second),
+	// 		},
+	// 	)
+
+	// 	if err != nil {
+	// 		return nil, err
+	// 	}
 
-		if err != nil {
-			return nil, err
-		}
+	// 	jwtTok = jwtSource.AccessToken
+	// }
+
+	gcp, err := repo.GCPIntegration.ReadGCPIntegration(
+		r.GCPIntegrationID,
+	)
 
-		jwtTok = jwtSource.AccessToken
+	if err != nil {
+		return nil, err
+	}
+
+	// get oauth2 access token
+	oauthTok, err := gcp.GetBearerToken(r.getTokenCache, r.setTokenCacheFunc(repo))
+
+	if err != nil {
+		return nil, err
 	}
 
 	// use JWT token to request catalog
@@ -137,7 +152,9 @@ func (r *Registry) listGCRRepositories(
 		return nil, err
 	}
 
-	req.Header.Add("Authorization", "Bearer "+jwtTok)
+	req.SetBasicAuth("oauth2accesstoken", oauthTok)
+
+	// req.Header.Add("Authorization", "Bearer "+jwtTok)
 
 	resp, err := client.Do(req)
 
@@ -198,15 +215,19 @@ func (r *Registry) listECRRepositories(repo repository.Repository) ([]*Repositor
 }
 
 func (r *Registry) getTokenCache() (tok *ints.TokenCache, err error) {
-	return &r.IntTokenCache, nil
+	return &ints.TokenCache{
+		RegistryID: r.TokenCache.RegistryID,
+		Token:      r.TokenCache.Token,
+		Expiry:     r.TokenCache.Expiry,
+	}, nil
 }
 
 func (r *Registry) setTokenCacheFunc(
 	repo repository.Repository,
 ) ints.SetTokenCacheFunc {
 	return func(token string, expiry time.Time) error {
-		_, err := repo.Registry.UpdateRegistryIntTokenCache(
-			&ints.TokenCache{
+		_, err := repo.Registry.UpdateRegistryTokenCache(
+			&ints.RegTokenCache{
 				RegistryID: r.ID,
 				Token:      []byte(token),
 				Expiry:     expiry,
@@ -227,6 +248,10 @@ func (r *Registry) ListImages(
 		return r.listECRImages(repoName, repo)
 	}
 
+	if r.GCPIntegrationID != 0 {
+		return r.listGCRImages(repoName, repo)
+	}
+
 	return nil, fmt.Errorf("error listing images")
 }
 
@@ -267,3 +292,62 @@ func (r *Registry) listECRImages(repoName string, repo repository.Repository) ([
 
 	return res, nil
 }
+
+type gcrImageResp struct {
+	Tags []string `json:"tags"`
+}
+
+func (r *Registry) listGCRImages(repoName string, repo repository.Repository) ([]*Image, error) {
+	gcp, err := repo.GCPIntegration.ReadGCPIntegration(
+		r.GCPIntegrationID,
+	)
+
+	if err != nil {
+		return nil, err
+	}
+
+	// get oauth2 access token
+	oauthTok, err := gcp.GetBearerToken(r.getTokenCache, r.setTokenCacheFunc(repo))
+
+	if err != nil {
+		return nil, err
+	}
+
+	// use JWT token to request catalog
+	client := &http.Client{}
+
+	req, err := http.NewRequest(
+		"GET",
+		fmt.Sprintf("https://gcr.io/v2/%s/tags/list", repoName),
+		nil,
+	)
+
+	if err != nil {
+		return nil, err
+	}
+
+	req.SetBasicAuth("oauth2accesstoken", oauthTok)
+
+	resp, err := client.Do(req)
+
+	if err != nil {
+		return nil, err
+	}
+
+	gcrResp := gcrImageResp{}
+
+	if err := json.NewDecoder(resp.Body).Decode(&gcrResp); err != nil {
+		return nil, fmt.Errorf("Could not read GCR repositories: %v", err)
+	}
+
+	res := make([]*Image, 0)
+
+	for _, tag := range gcrResp.Tags {
+		res = append(res, &Image{
+			RepositoryName: repoName,
+			Tag:            tag,
+		})
+	}
+
+	return res, nil
+}

+ 12 - 72
internal/repository/gorm/registry.go

@@ -44,23 +44,13 @@ func (repo *RegistryRepository) CreateRegistry(reg *models.Registry) (*models.Re
 	}
 
 	// create a token cache by default
-	assoc = repo.db.Model(reg).Association("IntTokenCache")
+	assoc = repo.db.Model(reg).Association("TokenCache")
 
 	if assoc.Error != nil {
 		return nil, assoc.Error
 	}
 
-	if err := assoc.Append(&reg.IntTokenCache); err != nil {
-		return nil, err
-	}
-
-	assoc = repo.db.Model(reg).Association("DockerTokenCache")
-
-	if assoc.Error != nil {
-		return nil, assoc.Error
-	}
-
-	if err := assoc.Append(&reg.DockerTokenCache); err != nil {
+	if err := assoc.Append(&reg.TokenCache); err != nil {
 		return nil, err
 	}
 
@@ -77,7 +67,7 @@ func (repo *RegistryRepository) CreateRegistry(reg *models.Registry) (*models.Re
 func (repo *RegistryRepository) ReadRegistry(id uint) (*models.Registry, error) {
 	reg := &models.Registry{}
 
-	if err := repo.db.Preload("IntTokenCache").Preload("DockerTokenCache").Where("id = ?", id).First(&reg).Error; err != nil {
+	if err := repo.db.Preload("TokenCache").Where("id = ?", id).First(&reg).Error; err != nil {
 		return nil, err
 	}
 
@@ -93,7 +83,7 @@ func (repo *RegistryRepository) ListRegistriesByProjectID(
 ) ([]*models.Registry, error) {
 	regs := []*models.Registry{}
 
-	if err := repo.db.Preload("IntTokenCache").Preload("DockerTokenCache").Where("project_id = ?", projectID).Find(&regs).Error; err != nil {
+	if err := repo.db.Preload("TokenCache").Where("project_id = ?", projectID).Find(&regs).Error; err != nil {
 		return nil, err
 	}
 
@@ -104,38 +94,8 @@ func (repo *RegistryRepository) ListRegistriesByProjectID(
 	return regs, nil
 }
 
-// UpdateRegistryIntTokenCache updates the token cache for a registry
-func (repo *RegistryRepository) UpdateRegistryIntTokenCache(
-	tokenCache *ints.TokenCache,
-) (*models.Registry, error) {
-	if tok := tokenCache.Token; len(tok) > 0 {
-		cipherData, err := repository.Encrypt(tok, repo.key)
-
-		if err != nil {
-			return nil, err
-		}
-
-		tokenCache.Token = cipherData
-	}
-
-	registry := &models.Registry{}
-
-	if err := repo.db.Where("id = ?", tokenCache.RegistryID).First(&registry).Error; err != nil {
-		return nil, err
-	}
-
-	registry.IntTokenCache.Token = tokenCache.Token
-	registry.IntTokenCache.Expiry = tokenCache.Expiry
-
-	if err := repo.db.Save(registry).Error; err != nil {
-		return nil, err
-	}
-
-	return registry, nil
-}
-
-// UpdateRegistryDockerTokenCache updates the token cache for a registry
-func (repo *RegistryRepository) UpdateRegistryDockerTokenCache(
+// UpdateRegistryTokenCache updates the token cache for a registry
+func (repo *RegistryRepository) UpdateRegistryTokenCache(
 	tokenCache *ints.RegTokenCache,
 ) (*models.Registry, error) {
 	if tok := tokenCache.Token; len(tok) > 0 {
@@ -154,8 +114,8 @@ func (repo *RegistryRepository) UpdateRegistryDockerTokenCache(
 		return nil, err
 	}
 
-	registry.DockerTokenCache.Token = tokenCache.Token
-	registry.DockerTokenCache.Expiry = tokenCache.Expiry
+	registry.TokenCache.Token = tokenCache.Token
+	registry.TokenCache.Expiry = tokenCache.Expiry
 
 	if err := repo.db.Save(registry).Error; err != nil {
 		return nil, err
@@ -170,24 +130,14 @@ func (repo *RegistryRepository) EncryptRegistryData(
 	registry *models.Registry,
 	key *[32]byte,
 ) error {
-	if tok := registry.IntTokenCache.Token; len(tok) > 0 {
-		cipherData, err := repository.Encrypt(tok, key)
-
-		if err != nil {
-			return err
-		}
-
-		registry.IntTokenCache.Token = cipherData
-	}
-
-	if tok := registry.DockerTokenCache.Token; len(tok) > 0 {
+	if tok := registry.TokenCache.Token; len(tok) > 0 {
 		cipherData, err := repository.Encrypt(tok, key)
 
 		if err != nil {
 			return err
 		}
 
-		registry.DockerTokenCache.Token = cipherData
+		registry.TokenCache.Token = cipherData
 	}
 
 	return nil
@@ -199,24 +149,14 @@ func (repo *RegistryRepository) DecryptRegistryData(
 	registry *models.Registry,
 	key *[32]byte,
 ) error {
-	if tok := registry.IntTokenCache.Token; len(tok) > 0 {
-		plaintext, err := repository.Decrypt(tok, key)
-
-		if err != nil {
-			return err
-		}
-
-		registry.IntTokenCache.Token = plaintext
-	}
-
-	if tok := registry.DockerTokenCache.Token; len(tok) > 0 {
+	if tok := registry.TokenCache.Token; len(tok) > 0 {
 		plaintext, err := repository.Decrypt(tok, key)
 
 		if err != nil {
 			return err
 		}
 
-		registry.DockerTokenCache.Token = plaintext
+		registry.TokenCache.Token = plaintext
 	}
 
 	return nil

+ 14 - 62
internal/repository/gorm/registry_test.go

@@ -97,14 +97,10 @@ func TestUpdateRegistryToken(t *testing.T) {
 	reg := &models.Registry{
 		Name:      "registry-test",
 		ProjectID: tester.initProjects[0].Model.ID,
-		IntTokenCache: ints.TokenCache{
+		TokenCache: ints.RegTokenCache{
 			Token:  []byte("token-1"),
 			Expiry: time.Now().Add(-1 * time.Hour),
 		},
-		DockerTokenCache: ints.RegTokenCache{
-			Token:  []byte("docker-token-1"),
-			Expiry: time.Now().Add(-1 * time.Hour),
-		},
 	}
 
 	reg, err := tester.repo.Registry.CreateRegistry(reg)
@@ -120,67 +116,23 @@ func TestUpdateRegistryToken(t *testing.T) {
 	}
 
 	// make sure registry id of token is 1
-	if reg.IntTokenCache.RegistryID != 1 {
-		t.Fatalf("incorrect registry id in token cache: expected %d, got %d\n", 1, reg.IntTokenCache.RegistryID)
-	}
-
-	// make sure old token is expired
-	if isExpired := reg.IntTokenCache.IsExpired(); !isExpired {
-		t.Fatalf("token was not expired\n")
-	}
-
-	if string(reg.IntTokenCache.Token) != "token-1" {
-		t.Errorf("incorrect token in cache: expected %s, got %s\n", "token-1", reg.IntTokenCache.Token)
-	}
-
-	reg.IntTokenCache.Token = []byte("token-2")
-	reg.IntTokenCache.Expiry = time.Now().Add(24 * time.Hour)
-
-	reg, err = tester.repo.Registry.UpdateRegistryIntTokenCache(&reg.IntTokenCache)
-	if err != nil {
-		t.Fatalf("%v\n", err)
-	}
-	reg, err = tester.repo.Registry.ReadRegistry(reg.Model.ID)
-	if err != nil {
-		t.Fatalf("%v\n", err)
-	}
-
-	// make sure id is 1
-	if reg.Model.ID != 1 {
-		t.Errorf("incorrect registry ID: expected %d, got %d\n", 1, reg.Model.ID)
-	}
-
-	// make sure new token is correct and not expired
-	if reg.IntTokenCache.RegistryID != 1 {
-		t.Fatalf("incorrect registry ID in token cache: expected %d, got %d\n", 1, reg.IntTokenCache.RegistryID)
-	}
-
-	if isExpired := reg.IntTokenCache.IsExpired(); isExpired {
-		t.Fatalf("token was expired\n")
-	}
-
-	if string(reg.IntTokenCache.Token) != "token-2" {
-		t.Errorf("incorrect token in cache: expected %s, got %s\n", "token-2", reg.IntTokenCache.Token)
-	}
-
-	// make sure registry id of docker token is 1
-	if reg.DockerTokenCache.RegistryID != 1 {
-		t.Fatalf("incorrect registry id in token cache: expected %d, got %d\n", 1, reg.DockerTokenCache.RegistryID)
+	if reg.TokenCache.RegistryID != 1 {
+		t.Fatalf("incorrect registry id in token cache: expected %d, got %d\n", 1, reg.TokenCache.RegistryID)
 	}
 
 	// make sure old token is expired
-	if isExpired := reg.DockerTokenCache.IsExpired(); !isExpired {
+	if isExpired := reg.TokenCache.IsExpired(); !isExpired {
 		t.Fatalf("token was not expired\n")
 	}
 
-	if string(reg.DockerTokenCache.Token) != "docker-token-1" {
-		t.Errorf("incorrect token in cache: expected %s, got %s\n", "docker-token-1", reg.DockerTokenCache.Token)
+	if string(reg.TokenCache.Token) != "token-1" {
+		t.Errorf("incorrect token in cache: expected %s, got %s\n", "token-1", reg.TokenCache.Token)
 	}
 
-	reg.DockerTokenCache.Token = []byte("docker-token-2")
-	reg.DockerTokenCache.Expiry = time.Now().Add(24 * time.Hour)
+	reg.TokenCache.Token = []byte("token-2")
+	reg.TokenCache.Expiry = time.Now().Add(24 * time.Hour)
 
-	reg, err = tester.repo.Registry.UpdateRegistryDockerTokenCache(&reg.DockerTokenCache)
+	reg, err = tester.repo.Registry.UpdateRegistryTokenCache(&reg.TokenCache)
 	if err != nil {
 		t.Fatalf("%v\n", err)
 	}
@@ -195,15 +147,15 @@ func TestUpdateRegistryToken(t *testing.T) {
 	}
 
 	// make sure new token is correct and not expired
-	if reg.DockerTokenCache.RegistryID != 1 {
-		t.Fatalf("incorrect registry ID in token cache: expected %d, got %d\n", 1, reg.DockerTokenCache.RegistryID)
+	if reg.TokenCache.RegistryID != 1 {
+		t.Fatalf("incorrect registry ID in token cache: expected %d, got %d\n", 1, reg.TokenCache.RegistryID)
 	}
 
-	if isExpired := reg.DockerTokenCache.IsExpired(); isExpired {
+	if isExpired := reg.TokenCache.IsExpired(); isExpired {
 		t.Fatalf("token was expired\n")
 	}
 
-	if string(reg.DockerTokenCache.Token) != "docker-token-2" {
-		t.Errorf("incorrect token in cache: expected %s, got %s\n", "docker-token-2", reg.DockerTokenCache.Token)
+	if string(reg.TokenCache.Token) != "token-2" {
+		t.Errorf("incorrect token in cache: expected %s, got %s\n", "token-2", reg.TokenCache.Token)
 	}
 }

+ 1 - 2
internal/repository/registry.go

@@ -10,6 +10,5 @@ type RegistryRepository interface {
 	CreateRegistry(reg *models.Registry) (*models.Registry, error)
 	ReadRegistry(id uint) (*models.Registry, error)
 	ListRegistriesByProjectID(projectID uint) ([]*models.Registry, error)
-	UpdateRegistryIntTokenCache(tokenCache *ints.TokenCache) (*models.Registry, error)
-	UpdateRegistryDockerTokenCache(tokenCache *ints.RegTokenCache) (*models.Registry, error)
+	UpdateRegistryTokenCache(tokenCache *ints.RegTokenCache) (*models.Registry, error)
 }

+ 4 - 19
internal/repository/test/registry.go

@@ -73,23 +73,8 @@ func (repo *RegistryRepository) ListRegistriesByProjectID(
 	return res, nil
 }
 
-// UpdateRegistryIntTokenCache updates the token cache for a registry
-func (repo *RegistryRepository) UpdateRegistryIntTokenCache(
-	tokenCache *ints.TokenCache,
-) (*models.Registry, error) {
-	if !repo.canQuery {
-		return nil, errors.New("Cannot write database")
-	}
-
-	index := int(tokenCache.RegistryID - 1)
-	repo.registries[index].IntTokenCache.Token = tokenCache.Token
-	repo.registries[index].IntTokenCache.Expiry = tokenCache.Expiry
-
-	return repo.registries[index], nil
-}
-
-// UpdateRegistryDockerTokenCache updates the token cache for a registry
-func (repo *RegistryRepository) UpdateRegistryDockerTokenCache(
+// UpdateRegistryTokenCache updates the token cache for a registry
+func (repo *RegistryRepository) UpdateRegistryTokenCache(
 	tokenCache *ints.RegTokenCache,
 ) (*models.Registry, error) {
 	if !repo.canQuery {
@@ -97,8 +82,8 @@ func (repo *RegistryRepository) UpdateRegistryDockerTokenCache(
 	}
 
 	index := int(tokenCache.RegistryID - 1)
-	repo.registries[index].DockerTokenCache.Token = tokenCache.Token
-	repo.registries[index].DockerTokenCache.Expiry = tokenCache.Expiry
+	repo.registries[index].TokenCache.Token = tokenCache.Token
+	repo.registries[index].TokenCache.Expiry = tokenCache.Expiry
 
 	return repo.registries[index], nil
 }

+ 1 - 1
server/api/registry_handler.go

@@ -139,7 +139,7 @@ func (app *App) HandleListImages(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 
-	repoName := chi.URLParam(r, "repo_name")
+	repoName := chi.URLParam(r, "*")
 
 	reg, err := app.repo.Registry.ReadRegistry(uint(regID))
 

+ 0 - 22
server/api/registry_handler_test.go

@@ -170,28 +170,6 @@ func TestHandleListRegistries(t *testing.T) {
 	testRegistryRequests(t, listRegistryTests, true)
 }
 
-var listImagesTests = []*imagesTest{
-	&imagesTest{
-		initializers: []func(tester *tester){
-			initDefaultImages,
-		},
-		msg:       "List images",
-		method:    "GET",
-		endpoint:  "/api/projects/1/images",
-		body:      "",
-		expStatus: http.StatusOK,
-		expBody:   "unimplemented",
-		useCookie: true,
-		validators: []func(c *imagesTest, tester *tester, t *testing.T){
-			imagesListValidator,
-		},
-	},
-}
-
-func TestHandleListImages(t *testing.T) {
-	testImagesRequests(t, listImagesTests, true)
-}
-
 // ------------------------- INITIALIZERS AND VALIDATORS ------------------------- //
 
 func initRegistry(tester *tester) {

+ 4 - 1
server/router/router.go

@@ -217,7 +217,10 @@ func New(
 
 		r.Method(
 			"GET",
-			"/projects/{project_id}/registries/{registry_id}/repositories/{repo_name}",
+			// * is the repo name, which can itself be nested
+			// for example, for GCR this is project-id/repo
+			// need to use wildcard, see https://github.com/go-chi/chi/issues/243
+			"/projects/{project_id}/registries/{registry_id}/repositories/*",
 			auth.DoesUserHaveProjectAccess(
 				auth.DoesUserHaveRegistryAccess(
 					requestlog.NewHandler(a.HandleListImages, l),