Sfoglia il codice sorgente

add create registry and repository endpoints

Alexander Belanger 4 anni fa
parent
commit
17e8eb3807

+ 1 - 4
api/server/handlers/helmrepo/get.go

@@ -3,7 +3,6 @@ package helmrepo
 import (
 	"net/http"
 
-	"github.com/porter-dev/porter/api/server/authz"
 	"github.com/porter-dev/porter/api/server/handlers"
 	"github.com/porter-dev/porter/api/server/shared"
 	"github.com/porter-dev/porter/api/server/shared/config"
@@ -13,7 +12,6 @@ import (
 
 type HelmRepoGetHandler struct {
 	handlers.PorterHandlerWriter
-	authz.KubernetesAgentGetter
 }
 
 func NewHelmRepoGetHandler(
@@ -21,8 +19,7 @@ func NewHelmRepoGetHandler(
 	writer shared.ResultWriter,
 ) *HelmRepoGetHandler {
 	return &HelmRepoGetHandler{
-		PorterHandlerWriter:   handlers.NewDefaultPorterHandler(config, nil, writer),
-		KubernetesAgentGetter: authz.NewOutOfClusterAgentGetter(config),
+		PorterHandlerWriter: handlers.NewDefaultPorterHandler(config, nil, writer),
 	}
 }
 

+ 1 - 4
api/server/handlers/infra/get.go

@@ -3,7 +3,6 @@ package infra
 import (
 	"net/http"
 
-	"github.com/porter-dev/porter/api/server/authz"
 	"github.com/porter-dev/porter/api/server/handlers"
 	"github.com/porter-dev/porter/api/server/shared"
 	"github.com/porter-dev/porter/api/server/shared/config"
@@ -13,7 +12,6 @@ import (
 
 type InfraGetHandler struct {
 	handlers.PorterHandlerWriter
-	authz.KubernetesAgentGetter
 }
 
 func NewInfraGetHandler(
@@ -21,8 +19,7 @@ func NewInfraGetHandler(
 	writer shared.ResultWriter,
 ) *InfraGetHandler {
 	return &InfraGetHandler{
-		PorterHandlerWriter:   handlers.NewDefaultPorterHandler(config, nil, writer),
-		KubernetesAgentGetter: authz.NewOutOfClusterAgentGetter(config),
+		PorterHandlerWriter: handlers.NewDefaultPorterHandler(config, nil, writer),
 	}
 }
 

+ 1 - 4
api/server/handlers/invite/get.go

@@ -3,7 +3,6 @@ package invite
 import (
 	"net/http"
 
-	"github.com/porter-dev/porter/api/server/authz"
 	"github.com/porter-dev/porter/api/server/handlers"
 	"github.com/porter-dev/porter/api/server/shared"
 	"github.com/porter-dev/porter/api/server/shared/config"
@@ -13,7 +12,6 @@ import (
 
 type InviteGetHandler struct {
 	handlers.PorterHandlerWriter
-	authz.KubernetesAgentGetter
 }
 
 func NewInviteGetHandler(
@@ -21,8 +19,7 @@ func NewInviteGetHandler(
 	writer shared.ResultWriter,
 ) *InviteGetHandler {
 	return &InviteGetHandler{
-		PorterHandlerWriter:   handlers.NewDefaultPorterHandler(config, nil, writer),
-		KubernetesAgentGetter: authz.NewOutOfClusterAgentGetter(config),
+		PorterHandlerWriter: handlers.NewDefaultPorterHandler(config, nil, writer),
 	}
 }
 

+ 71 - 0
api/server/handlers/registry/create.go

@@ -0,0 +1,71 @@
+package registry
+
+import (
+	"net/http"
+
+	"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/registry"
+)
+
+type RegistryCreateHandler struct {
+	handlers.PorterHandlerReadWriter
+}
+
+func NewRegistryCreateHandler(
+	config *config.Config,
+	decoderValidator shared.RequestDecoderValidator,
+	writer shared.ResultWriter,
+) *RegistryCreateHandler {
+	return &RegistryCreateHandler{
+		PorterHandlerReadWriter: handlers.NewDefaultPorterHandler(config, decoderValidator, writer),
+	}
+}
+
+func (p *RegistryCreateHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+	proj, _ := r.Context().Value(types.ProjectScope).(*models.Project)
+
+	request := &types.CreateRegistryRequest{}
+
+	ok := p.DecodeAndValidate(w, r, request)
+
+	if !ok {
+		return
+	}
+
+	// create a registry model
+	regModel := &models.Registry{
+		Name:               request.Name,
+		ProjectID:          proj.ID,
+		URL:                request.URL,
+		GCPIntegrationID:   request.GCPIntegrationID,
+		AWSIntegrationID:   request.AWSIntegrationID,
+		DOIntegrationID:    request.DOIntegrationID,
+		BasicIntegrationID: request.BasicIntegrationID,
+	}
+
+	if regModel.URL == "" && regModel.AWSIntegrationID != 0 {
+		url, err := registry.GetECRRegistryURL(p.Repo().AWSIntegration(), regModel.AWSIntegrationID)
+
+		if err != nil {
+			p.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+			return
+		}
+
+		regModel.URL = url
+	}
+
+	// handle write to the database
+	regModel, err := p.Repo().Registry().CreateRegistry(regModel)
+
+	if err != nil {
+		p.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+		return
+	}
+
+	p.WriteResult(w, r, regModel.ToRegistryType())
+}

+ 54 - 0
api/server/handlers/registry/create_repository.go

@@ -0,0 +1,54 @@
+package registry
+
+import (
+	"net/http"
+	"strings"
+
+	"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/registry"
+)
+
+type RegistryCreateRepositoryHandler struct {
+	handlers.PorterHandlerReadWriter
+}
+
+func NewRegistryCreateRepositoryHandler(
+	config *config.Config,
+	decoderValidator shared.RequestDecoderValidator,
+	writer shared.ResultWriter,
+) *RegistryCreateRepositoryHandler {
+	return &RegistryCreateRepositoryHandler{
+		PorterHandlerReadWriter: handlers.NewDefaultPorterHandler(config, decoderValidator, writer),
+	}
+}
+
+func (p *RegistryCreateRepositoryHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+	reg, _ := r.Context().Value(types.RegistryScope).(*models.Registry)
+
+	request := &types.CreateRegistryRepositoryRequest{}
+
+	ok := p.DecodeAndValidate(w, r, request)
+
+	if !ok {
+		return
+	}
+
+	_reg := registry.Registry(*reg)
+	regAPI := &_reg
+
+	// parse the name from the registry
+	nameSpl := strings.Split(request.ImageRepoURI, "/")
+	repoName := nameSpl[len(nameSpl)-1]
+
+	err := regAPI.CreateRepository(p.Repo(), repoName)
+
+	if err != nil {
+		p.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+		return
+	}
+}

+ 1 - 4
api/server/handlers/registry/get.go

@@ -3,7 +3,6 @@ package registry
 import (
 	"net/http"
 
-	"github.com/porter-dev/porter/api/server/authz"
 	"github.com/porter-dev/porter/api/server/handlers"
 	"github.com/porter-dev/porter/api/server/shared"
 	"github.com/porter-dev/porter/api/server/shared/config"
@@ -13,7 +12,6 @@ import (
 
 type RegistryGetHandler struct {
 	handlers.PorterHandlerWriter
-	authz.KubernetesAgentGetter
 }
 
 func NewRegistryGetHandler(
@@ -21,8 +19,7 @@ func NewRegistryGetHandler(
 	writer shared.ResultWriter,
 ) *RegistryGetHandler {
 	return &RegistryGetHandler{
-		PorterHandlerWriter:   handlers.NewDefaultPorterHandler(config, nil, writer),
-		KubernetesAgentGetter: authz.NewOutOfClusterAgentGetter(config),
+		PorterHandlerWriter: handlers.NewDefaultPorterHandler(config, nil, writer),
 	}
 }
 

+ 44 - 0
api/server/handlers/registry/list.go

@@ -0,0 +1,44 @@
+package registry
+
+import (
+	"net/http"
+
+	"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"
+)
+
+type RegistryListHandler struct {
+	handlers.PorterHandlerWriter
+}
+
+func NewRegistryListHandler(
+	config *config.Config,
+	writer shared.ResultWriter,
+) *RegistryListHandler {
+	return &RegistryListHandler{
+		PorterHandlerWriter: handlers.NewDefaultPorterHandler(config, nil, writer),
+	}
+}
+
+func (c *RegistryListHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+	proj, _ := r.Context().Value(types.ProjectScope).(*models.Project)
+
+	regs, err := c.Repo().Registry().ListRegistriesByProjectID(proj.ID)
+
+	if err != nil {
+		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+		return
+	}
+
+	extRegs := make(types.RegistryListResponse, 0)
+
+	for _, reg := range regs {
+		extRegs = append(extRegs, *reg.ToRegistryType())
+	}
+
+	c.WriteResult(w, r, extRegs)
+}

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

@@ -5,6 +5,7 @@ import (
 	"github.com/porter-dev/porter/api/server/handlers/cluster"
 	"github.com/porter-dev/porter/api/server/handlers/gitinstallation"
 	"github.com/porter-dev/porter/api/server/handlers/project"
+	"github.com/porter-dev/porter/api/server/handlers/registry"
 	"github.com/porter-dev/porter/api/server/shared"
 	"github.com/porter-dev/porter/api/server/shared/config"
 	"github.com/porter-dev/porter/api/types"
@@ -189,5 +190,60 @@ func getProjectRoutes(
 		Router:   r,
 	})
 
+	// GET /api/projects/{project_id}/registries -> registry.NewRegistryListHandler
+	listRegistriesEndpoint := factory.NewAPIEndpoint(
+		&types.APIRequestMetadata{
+			Verb:   types.APIVerbList,
+			Method: types.HTTPVerbGet,
+			Path: &types.Path{
+				Parent:       basePath,
+				RelativePath: relPath + "/registries",
+			},
+			Scopes: []types.PermissionScope{
+				types.UserScope,
+				types.ProjectScope,
+			},
+		},
+	)
+
+	listRegistriesHandler := registry.NewRegistryListHandler(
+		config,
+		factory.GetResultWriter(),
+	)
+
+	routes = append(routes, &Route{
+		Endpoint: listRegistriesEndpoint,
+		Handler:  listRegistriesHandler,
+		Router:   r,
+	})
+
+	// POST /api/projects/{project_id}/registries -> registry.NewRegistryCreateHandler
+	createRegistryEndpoint := factory.NewAPIEndpoint(
+		&types.APIRequestMetadata{
+			Verb:   types.APIVerbCreate,
+			Method: types.HTTPVerbPost,
+			Path: &types.Path{
+				Parent:       basePath,
+				RelativePath: relPath + "/registries",
+			},
+			Scopes: []types.PermissionScope{
+				types.UserScope,
+				types.ProjectScope,
+			},
+		},
+	)
+
+	createRegistryHandler := registry.NewRegistryCreateHandler(
+		config,
+		factory.GetDecoderValidator(),
+		factory.GetResultWriter(),
+	)
+
+	routes = append(routes, &Route{
+		Endpoint: createRegistryEndpoint,
+		Handler:  createRegistryHandler,
+		Router:   r,
+	})
+
 	return routes, newPath
 }

+ 29 - 0
api/server/router/registry.go

@@ -80,5 +80,34 @@ func getRegistryRoutes(
 		Router:   r,
 	})
 
+	// POST /api/projects/{project_id}/registries/{registry_id}/repository -> registry.NewRegistryCreateRepositoryHandler
+	createRepositoryEndpoint := factory.NewAPIEndpoint(
+		&types.APIRequestMetadata{
+			Verb:   types.APIVerbCreate,
+			Method: types.HTTPVerbPost,
+			Path: &types.Path{
+				Parent:       basePath,
+				RelativePath: relPath + "/repository",
+			},
+			Scopes: []types.PermissionScope{
+				types.UserScope,
+				types.ProjectScope,
+				types.RegistryScope,
+			},
+		},
+	)
+
+	createRepositoryHandler := registry.NewRegistryCreateRepositoryHandler(
+		config,
+		factory.GetDecoderValidator(),
+		factory.GetResultWriter(),
+	)
+
+	routes = append(routes, &Route{
+		Endpoint: createRepositoryEndpoint,
+		Handler:  createRepositoryHandler,
+		Router:   r,
+	})
+
 	return routes, newPath
 }

+ 15 - 0
api/types/registry.go

@@ -27,3 +27,18 @@ const (
 	DOCR      RegistryService = "docr"
 	DockerHub RegistryService = "dockerhub"
 )
+
+type RegistryListResponse []Registry
+
+type CreateRegistryRequest struct {
+	URL                string `json:"url"`
+	Name               string `json:"name" form:"required"`
+	GCPIntegrationID   uint   `json:"gcp_integration_id"`
+	AWSIntegrationID   uint   `json:"aws_integration_id"`
+	DOIntegrationID    uint   `json:"do_integration_id"`
+	BasicIntegrationID uint   `json:"basic_integration_id"`
+}
+
+type CreateRegistryRepositoryRequest struct {
+	ImageRepoURI string `json:"image_repo_uri" form:"required"`
+}

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

@@ -112,8 +112,8 @@
 | <li>- [ ] `POST /api/projects/{project_id}/provision/gke`                                                                   |             |                 |             |                  |
 | <li>- [ ] `POST /api/projects/{project_id}/provision/test`                                                                  |             |                 |             |                  |
 | <li>- [ ] `GET /api/projects/{project_id}/provision/{kind}/{infra_id}/logs`                                                 |             |                 |             |                  |
-| <li>- [ ] `POST /api/projects/{project_id}/registries`                                                                      |             |                 |             |                  |
-| <li>- [ ] `GET /api/projects/{project_id}/registries`                                                                       |             |                 |             |                  |
+| <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`                                                    |             |                 |             |                  |
@@ -122,7 +122,7 @@
 | <li>- [ ] `POST /api/projects/{project_id}/registries/{registry_id}`                                                        |             |                 |             |                  |
 | <li>- [ ] `GET /api/projects/{project_id}/registries/{registry_id}/repositories`                                            |             |                 |             |                  |
 | <li>- [ ] `GET /api/projects/{project_id}/registries/{registry_id}/repositories/*`                                          |             |                 |             |                  |
-| <li>- [ ] `POST /api/projects/{project_id}/registries/{registry_id}/repository`                                             |             |                 |             |                  |
+| <li>- [X] `POST /api/projects/{project_id}/registries/{registry_id}/repository`                                             | AB          |                 |             |                  |
 | <li>- [x] `GET /api/projects/{project_id}/releases`                                                                         | AS          | yes             |             | yes              |
 | <li>- [ ] `POST /api/projects/{project_id}/releases/image/update/batch`                                                     |             |                 |             |                  |
 | <li>- [ ] `GET /api/projects/{project_id}/releases/{name}/history`                                                          |             |                 |             |                  |

+ 24 - 0
internal/registry/registry.go

@@ -57,6 +57,30 @@ type Image struct {
 	PushedAt *time.Time `json:"pushed_at"`
 }
 
+func GetECRRegistryURL(awsIntRepo repository.AWSIntegrationRepository, awsIntID uint) (string, error) {
+	awsInt, err := awsIntRepo.ReadAWSIntegration(awsIntID)
+
+	if err != nil {
+		return "", err
+	}
+
+	sess, err := awsInt.GetSession()
+
+	if err != nil {
+		return "", err
+	}
+
+	ecrSvc := ecr.New(sess)
+
+	output, err := ecrSvc.GetAuthorizationToken(&ecr.GetAuthorizationTokenInput{})
+
+	if err != nil {
+		return "", err
+	}
+
+	return *output.AuthorizationData[0].ProxyEndpoint, nil
+}
+
 // ListRepositories lists the repositories for a registry
 func (r *Registry) ListRepositories(
 	repo repository.Repository,