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

add registry get token endpoints

Alexander Belanger 4 лет назад
Родитель
Сommit
255959ea45

+ 5 - 5
api/client/registry.go

@@ -275,7 +275,7 @@ func (c *Client) GetECRAuthorizationToken(
 ) (*GetTokenResponse, error) {
 	req, err := http.NewRequest(
 		"GET",
-		fmt.Sprintf("%s/projects/%d/registries/ecr/%s/token", c.BaseURL, projectID, region),
+		fmt.Sprintf("%s/projects/%d/registries/ecr/token?region=%s", c.BaseURL, projectID, region),
 		nil,
 	)
 
@@ -315,8 +315,8 @@ func (c *Client) GetGCRAuthorizationToken(
 
 	req, err := http.NewRequest(
 		"GET",
-		fmt.Sprintf("%s/projects/%d/registries/gcr/token", c.BaseURL, projectID),
-		strings.NewReader(string(data)),
+		fmt.Sprintf("%s/projects/%d/registries/gcr/token?server_url=%s", c.BaseURL, projectID, gcrRequest.ServerURL),
+		nil,
 	)
 
 	if err != nil {
@@ -384,8 +384,8 @@ func (c *Client) GetDOCRAuthorizationToken(
 
 	req, err := http.NewRequest(
 		"GET",
-		fmt.Sprintf("%s/projects/%d/registries/docr/token", c.BaseURL, projectID),
-		strings.NewReader(string(data)),
+		fmt.Sprintf("%s/projects/%d/registries/docr/token?server_url=%s", c.BaseURL, projectID, docrRequest.ServerURL),
+		nil,
 	)
 
 	if err != nil {

+ 374 - 0
api/server/handlers/registry/get_token.go

@@ -0,0 +1,374 @@
+package registry
+
+import (
+	"encoding/base64"
+	"net/http"
+	"strings"
+	"time"
+
+	"github.com/aws/aws-sdk-go/service/ecr"
+	"github.com/porter-dev/porter/api/server/handlers"
+	"github.com/porter-dev/porter/api/server/shared"
+	"github.com/porter-dev/porter/api/server/shared/apierrors"
+	"github.com/porter-dev/porter/api/server/shared/config"
+	"github.com/porter-dev/porter/api/types"
+	"github.com/porter-dev/porter/internal/models"
+	"github.com/porter-dev/porter/internal/oauth"
+	"github.com/porter-dev/porter/internal/registry"
+)
+
+type RegistryGetECRTokenHandler struct {
+	handlers.PorterHandlerReadWriter
+}
+
+func NewRegistryGetECRTokenHandler(
+	config *config.Config,
+	decoderValidator shared.RequestDecoderValidator,
+	writer shared.ResultWriter,
+) *RegistryGetECRTokenHandler {
+	return &RegistryGetECRTokenHandler{
+		PorterHandlerReadWriter: handlers.NewDefaultPorterHandler(config, decoderValidator, writer),
+	}
+}
+
+func (c *RegistryGetECRTokenHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+	proj, _ := r.Context().Value(types.ProjectScope).(*models.Project)
+
+	request := &types.GetRegistryECRTokenRequest{}
+
+	if ok := c.DecodeAndValidate(w, r, request); !ok {
+		return
+	}
+
+	// list registries and find one that matches the region
+	regs, err := c.Repo().Registry().ListRegistriesByProjectID(proj.ID)
+
+	if err != nil {
+		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+		return
+	}
+
+	var token string
+	var expiresAt *time.Time
+
+	for _, reg := range regs {
+		if reg.AWSIntegrationID != 0 {
+			awsInt, err := c.Repo().AWSIntegration().ReadAWSIntegration(reg.AWSIntegrationID)
+
+			if err != nil {
+				c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+				return
+			}
+
+			if awsInt.AWSRegion == request.Region {
+				// get the aws integration and session
+				sess, err := awsInt.GetSession()
+
+				if err != nil {
+					c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+					return
+				}
+
+				ecrSvc := ecr.New(sess)
+
+				output, err := ecrSvc.GetAuthorizationToken(&ecr.GetAuthorizationTokenInput{})
+
+				if err != nil {
+					c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+					return
+				}
+
+				token = *output.AuthorizationData[0].AuthorizationToken
+				expiresAt = output.AuthorizationData[0].ExpiresAt
+			}
+		}
+	}
+
+	resp := &types.GetRegistryTokenResponse{
+		Token:     token,
+		ExpiresAt: expiresAt,
+	}
+
+	c.WriteResult(w, r, resp)
+}
+
+type RegistryGetGCRTokenHandler struct {
+	handlers.PorterHandlerReadWriter
+}
+
+func NewRegistryGetGCRTokenHandler(
+	config *config.Config,
+	decoderValidator shared.RequestDecoderValidator,
+	writer shared.ResultWriter,
+) *RegistryGetGCRTokenHandler {
+	return &RegistryGetGCRTokenHandler{
+		PorterHandlerReadWriter: handlers.NewDefaultPorterHandler(config, decoderValidator, writer),
+	}
+}
+
+func (c *RegistryGetGCRTokenHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+	proj, _ := r.Context().Value(types.ProjectScope).(*models.Project)
+
+	request := &types.GetRegistryGCRTokenRequest{}
+
+	if ok := c.DecodeAndValidate(w, r, request); !ok {
+		return
+	}
+
+	// list registries and find one that matches the region
+	regs, err := c.Repo().Registry().ListRegistriesByProjectID(proj.ID)
+
+	if err != nil {
+		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+		return
+	}
+
+	var token string
+	var expiresAt *time.Time
+
+	for _, reg := range regs {
+		if reg.GCPIntegrationID != 0 && strings.Contains(reg.URL, request.ServerURL) {
+			_reg := registry.Registry(*reg)
+
+			tokenCache, err := _reg.GetGCRToken(c.Repo())
+
+			if err != nil {
+				c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+				return
+			}
+
+			token = string(tokenCache.Token)
+			expiresAt = &tokenCache.Expiry
+			break
+		}
+	}
+
+	resp := &types.GetRegistryTokenResponse{
+		Token:     token,
+		ExpiresAt: expiresAt,
+	}
+
+	c.WriteResult(w, r, resp)
+}
+
+type RegistryGetDOCRTokenHandler struct {
+	handlers.PorterHandlerReadWriter
+}
+
+func NewRegistryGetDOCRTokenHandler(
+	config *config.Config,
+	decoderValidator shared.RequestDecoderValidator,
+	writer shared.ResultWriter,
+) *RegistryGetDOCRTokenHandler {
+	return &RegistryGetDOCRTokenHandler{
+		PorterHandlerReadWriter: handlers.NewDefaultPorterHandler(config, decoderValidator, writer),
+	}
+}
+
+func (c *RegistryGetDOCRTokenHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+	proj, _ := r.Context().Value(types.ProjectScope).(*models.Project)
+
+	request := &types.GetRegistryDOCRTokenRequest{}
+
+	if ok := c.DecodeAndValidate(w, r, request); !ok {
+		return
+	}
+
+	// list registries and find one that matches the region
+	regs, err := c.Repo().Registry().ListRegistriesByProjectID(proj.ID)
+
+	if err != nil {
+		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+		return
+	}
+
+	var token string
+	var expiresAt *time.Time
+
+	for _, reg := range regs {
+		if reg.DOIntegrationID != 0 && strings.Contains(reg.URL, request.ServerURL) {
+			oauthInt, err := c.Repo().OAuthIntegration().ReadOAuthIntegration(reg.DOIntegrationID)
+
+			if err != nil {
+				c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+				return
+			}
+
+			tok, expiry, err := oauth.GetAccessToken(
+				oauthInt.SharedOAuthModel,
+				c.Config().DOConf,
+				oauth.MakeUpdateOAuthIntegrationTokenFunction(oauthInt, c.Repo()),
+			)
+
+			if err != nil {
+				c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+				return
+			}
+
+			token = tok
+			expiresAt = expiry
+			break
+		}
+	}
+
+	resp := &types.GetRegistryTokenResponse{
+		Token:     token,
+		ExpiresAt: expiresAt,
+	}
+
+	c.WriteResult(w, r, resp)
+}
+
+type RegistryGetDockerhubTokenHandler struct {
+	handlers.PorterHandlerReadWriter
+}
+
+func NewRegistryGetDockerhubTokenHandler(
+	config *config.Config,
+	decoderValidator shared.RequestDecoderValidator,
+	writer shared.ResultWriter,
+) *RegistryGetDockerhubTokenHandler {
+	return &RegistryGetDockerhubTokenHandler{
+		PorterHandlerReadWriter: handlers.NewDefaultPorterHandler(config, decoderValidator, writer),
+	}
+}
+
+func (c *RegistryGetDockerhubTokenHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+	proj, _ := r.Context().Value(types.ProjectScope).(*models.Project)
+
+	// list registries and find one that matches the region
+	regs, err := c.Repo().Registry().ListRegistriesByProjectID(proj.ID)
+
+	if err != nil {
+		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+		return
+	}
+
+	var token string
+	var expiresAt *time.Time
+
+	for _, reg := range regs {
+		if reg.BasicIntegrationID != 0 && strings.Contains(reg.URL, "index.docker.io") {
+			basic, err := c.Repo().BasicIntegration().ReadBasicIntegration(reg.BasicIntegrationID)
+
+			if err != nil {
+				c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+				return
+			}
+
+			token = base64.StdEncoding.EncodeToString([]byte(string(basic.Username) + ":" + string(basic.Password)))
+
+			// we'll just set an arbitrary 30-day expiry time (this is not enforced)
+			timeExpires := time.Now().Add(30 * 24 * 3600 * time.Second)
+			expiresAt = &timeExpires
+		}
+	}
+
+	resp := &types.GetRegistryTokenResponse{
+		Token:     token,
+		ExpiresAt: expiresAt,
+	}
+
+	c.WriteResult(w, r, resp)
+}
+
+// // HandleGetProjectRegistryDockerhubToken gets a Dockerhub token for a registry
+// func (app *App) HandleGetProjectRegistryDockerhubToken(w http.ResponseWriter, r *http.Request) {
+// 	projID, err := strconv.ParseUint(chi.URLParam(r, "project_id"), 0, 64)
+
+// 	if err != nil || projID == 0 {
+// 		app.handleErrorFormDecoding(err, ErrProjectDecode, w)
+// 		return
+// 	}
+
+// 	// list registries and find one that matches the region
+// 	regs, err := app.Repo.Registry().ListRegistriesByProjectID(uint(projID))
+// 	var token string
+// 	var expiresAt *time.Time
+
+// 	for _, reg := range regs {
+// 		if reg.BasicIntegrationID != 0 && strings.Contains(reg.URL, "index.docker.io") {
+// 			basic, err := app.Repo.BasicIntegration().ReadBasicIntegration(reg.BasicIntegrationID)
+
+// 			if err != nil {
+// 				app.handleErrorDataRead(err, w)
+// 				return
+// 			}
+
+// 			token = base64.StdEncoding.EncodeToString([]byte(string(basic.Username) + ":" + string(basic.Password)))
+
+// 			// we'll just set an arbitrary 30-day expiry time (this is not enforced)
+// 			timeExpires := time.Now().Add(30 * 24 * 3600 * time.Second)
+// 			expiresAt = &timeExpires
+// 		}
+// 	}
+
+// 	resp := &RegTokenResponse{
+// 		Token:     token,
+// 		ExpiresAt: expiresAt,
+// 	}
+
+// 	w.WriteHeader(http.StatusOK)
+
+// 	if err := json.NewEncoder(w).Encode(resp); err != nil {
+// 		app.handleErrorFormDecoding(err, ErrProjectDecode, w)
+// 		return
+// 	}
+// }
+
+// // HandleGetProjectRegistryDOCRToken gets a DOCR token for a registry
+// func (app *App) HandleGetProjectRegistryDOCRToken(w http.ResponseWriter, r *http.Request) {
+// 	projID, err := strconv.ParseUint(chi.URLParam(r, "project_id"), 0, 64)
+
+// 	if err != nil || projID == 0 {
+// 		app.handleErrorFormDecoding(err, ErrProjectDecode, w)
+// 		return
+// 	}
+
+// 	reqBody := &GCRTokenRequestBody{}
+
+// 	// decode from JSON to form value
+// 	if err := json.NewDecoder(r.Body).Decode(reqBody); err != nil {
+// 		app.handleErrorFormDecoding(err, ErrProjectDecode, w)
+// 		return
+// 	}
+
+// 	// list registries and find one that matches the region
+// 	regs, err := app.Repo.Registry().ListRegistriesByProjectID(uint(projID))
+// 	var token string
+// 	var expiresAt *time.Time
+
+// 	for _, reg := range regs {
+// 		if reg.DOIntegrationID != 0 && strings.Contains(reg.URL, reqBody.ServerURL) {
+// 			oauthInt, err := app.Repo.OAuthIntegration().ReadOAuthIntegration(reg.DOIntegrationID)
+
+// 			if err != nil {
+// 				app.handleErrorDataRead(err, w)
+// 				return
+// 			}
+
+// 			tok, expiry, err := oauth.GetAccessToken(oauthInt.SharedOAuthModel, app.DOConf, oauth.MakeUpdateOAuthIntegrationTokenFunction(oauthInt, app.Repo))
+
+// 			if err != nil {
+// 				app.handleErrorDataRead(err, w)
+// 				return
+// 			}
+
+// 			token = tok
+// 			expiresAt = expiry
+// 			break
+// 		}
+// 	}
+
+// 	resp := &RegTokenResponse{
+// 		Token:     token,
+// 		ExpiresAt: expiresAt,
+// 	}
+
+// 	w.WriteHeader(http.StatusOK)
+
+// 	if err := json.NewEncoder(w).Encode(resp); err != nil {
+// 		app.handleErrorFormDecoding(err, ErrProjectDecode, w)
+// 		return
+// 	}
+// }

+ 112 - 0
api/server/router/project.go

@@ -245,5 +245,117 @@ func getProjectRoutes(
 		Router:   r,
 	})
 
+	//  GET /api/projects/{project_id}/registries/ecr/token -> registry.NewRegistryGetECRTokenHandler
+	getECRTokenEndpoint := factory.NewAPIEndpoint(
+		&types.APIRequestMetadata{
+			Verb:   types.APIVerbGet,
+			Method: types.HTTPVerbGet,
+			Path: &types.Path{
+				Parent:       basePath,
+				RelativePath: relPath + "/registries/ecr/token",
+			},
+			Scopes: []types.PermissionScope{
+				types.UserScope,
+				types.ProjectScope,
+			},
+		},
+	)
+
+	getECRTokenHandler := registry.NewRegistryGetECRTokenHandler(
+		config,
+		factory.GetDecoderValidator(),
+		factory.GetResultWriter(),
+	)
+
+	routes = append(routes, &Route{
+		Endpoint: getECRTokenEndpoint,
+		Handler:  getECRTokenHandler,
+		Router:   r,
+	})
+
+	//  GET /api/projects/{project_id}/registries/docr/token -> registry.NewRegistryGetDOCRTokenHandler
+	getDOCRTokenEndpoint := factory.NewAPIEndpoint(
+		&types.APIRequestMetadata{
+			Verb:   types.APIVerbGet,
+			Method: types.HTTPVerbGet,
+			Path: &types.Path{
+				Parent:       basePath,
+				RelativePath: relPath + "/registries/docr/token",
+			},
+			Scopes: []types.PermissionScope{
+				types.UserScope,
+				types.ProjectScope,
+			},
+		},
+	)
+
+	getDOCRTokenHandler := registry.NewRegistryGetDOCRTokenHandler(
+		config,
+		factory.GetDecoderValidator(),
+		factory.GetResultWriter(),
+	)
+
+	routes = append(routes, &Route{
+		Endpoint: getDOCRTokenEndpoint,
+		Handler:  getDOCRTokenHandler,
+		Router:   r,
+	})
+
+	//  GET /api/projects/{project_id}/registries/gcr/token -> registry.NewRegistryGetGCRTokenHandler
+	getGCRTokenEndpoint := factory.NewAPIEndpoint(
+		&types.APIRequestMetadata{
+			Verb:   types.APIVerbGet,
+			Method: types.HTTPVerbGet,
+			Path: &types.Path{
+				Parent:       basePath,
+				RelativePath: relPath + "/registries/gcr/token",
+			},
+			Scopes: []types.PermissionScope{
+				types.UserScope,
+				types.ProjectScope,
+			},
+		},
+	)
+
+	getGCRTokenHandler := registry.NewRegistryGetGCRTokenHandler(
+		config,
+		factory.GetDecoderValidator(),
+		factory.GetResultWriter(),
+	)
+
+	routes = append(routes, &Route{
+		Endpoint: getGCRTokenEndpoint,
+		Handler:  getGCRTokenHandler,
+		Router:   r,
+	})
+
+	//  GET /api/projects/{project_id}/registries/dockerhub/token -> registry.NewRegistryGetDockerhubTokenHandler
+	getDockerhubTokenEndpoint := factory.NewAPIEndpoint(
+		&types.APIRequestMetadata{
+			Verb:   types.APIVerbGet,
+			Method: types.HTTPVerbGet,
+			Path: &types.Path{
+				Parent:       basePath,
+				RelativePath: relPath + "/registries/dockerhub/token",
+			},
+			Scopes: []types.PermissionScope{
+				types.UserScope,
+				types.ProjectScope,
+			},
+		},
+	)
+
+	getDockerhubTokenHandler := registry.NewRegistryGetDockerhubTokenHandler(
+		config,
+		factory.GetDecoderValidator(),
+		factory.GetResultWriter(),
+	)
+
+	routes = append(routes, &Route{
+		Endpoint: getDockerhubTokenEndpoint,
+		Handler:  getDockerhubTokenHandler,
+		Router:   r,
+	})
+
 	return routes, newPath
 }

+ 23 - 0
api/types/registry.go

@@ -1,5 +1,11 @@
 package types
 
+import "time"
+
+const (
+	URLParamRegion URLParam = "region"
+)
+
 type Registry struct {
 	ID uint `json:"id"`
 
@@ -48,3 +54,20 @@ type CreateRegistryRepositoryRequest struct {
 type UpdateRegistryRequest struct {
 	Name string `json:"name" form:"required"`
 }
+
+type GetRegistryTokenResponse struct {
+	Token     string     `json:"token"`
+	ExpiresAt *time.Time `json:"expires_at"`
+}
+
+type GetRegistryGCRTokenRequest struct {
+	ServerURL string `schema:"server_url"`
+}
+
+type GetRegistryECRTokenRequest struct {
+	Region string `schema:"region"`
+}
+
+type GetRegistryDOCRTokenRequest struct {
+	ServerURL string `schema:"server_url"`
+}

+ 4 - 4
docs/developing/backend-refactor-status.md

@@ -114,10 +114,10 @@
 | <li>- [ ] `GET /api/projects/{project_id}/provision/{kind}/{infra_id}/logs`                                                 |             |                 |             |                  |
 | <li>- [X] `POST /api/projects/{project_id}/registries`                                                                      | AB          |                 |             |                  |
 | <li>- [X] `GET /api/projects/{project_id}/registries`                                                                       | AB          |                 |             |                  |
-| <li>- [ ] `GET /api/projects/{project_id}/registries/dockerhub/token`                                                       |             |                 |             |                  |
-| <li>- [ ] `GET /api/projects/{project_id}/registries/docr/token`                                                            |             |                 |             |                  |
-| <li>- [ ] `GET /api/projects/{project_id}/registries/ecr/{region}/token`                                                    |             |                 |             |                  |
-| <li>- [ ] `GET /api/projects/{project_id}/registries/gcr/token`                                                             |             |                 |             |                  |
+| <li>- [X] `GET /api/projects/{project_id}/registries/dockerhub/token`                                                       | AB          |                 |             |                  |
+| <li>- [X] `GET /api/projects/{project_id}/registries/docr/token`                                                            | AB          |                 |             |                  |
+| <li>- [X] `GET /api/projects/{project_id}/registries/ecr/{region}/token`                                                    | AB          | yes             |             |                  |
+| <li>- [X] `GET /api/projects/{project_id}/registries/gcr/token`                                                             |             |                 |             |                  |
 | <li>- [X] `DELETE /api/projects/{project_id}/registries/{registry_id}`                                                      | AB          |                 |             |                  |
 | <li>- [X] `POST /api/projects/{project_id}/registries/{registry_id}`                                                        | AB          |                 |             |                  |
 | <li>- [X] `GET /api/projects/{project_id}/registries/{registry_id}/repositories`                                            | AB          |                 |             |                  |