Bladeren bron

add provision eks and ecr endpoints

Alexander Belanger 4 jaren geleden
bovenliggende
commit
6c48395243

+ 68 - 101
api/server/handlers/provision/provision_ecr.go

@@ -5,7 +5,14 @@ import (
 
 	"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/kubernetes"
+	"github.com/porter-dev/porter/internal/kubernetes/provisioner"
+	"github.com/porter-dev/porter/internal/models"
+	"github.com/porter-dev/porter/internal/repository"
+	"gorm.io/gorm"
 )
 
 type ProvisionECRHandler struct {
@@ -24,112 +31,72 @@ func NewProvisionECRHandler(
 
 func (c *ProvisionECRHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 	// read the project from context
-	// proj, _ := r.Context().Value(types.ProjectScope).(*models.Project)
+	proj, _ := r.Context().Value(types.ProjectScope).(*models.Project)
 
-	// request := &types.CreateClusterManualRequest{}
+	request := &types.CreateECRInfraRequest{}
 
-	// if ok := c.DecodeAndValidate(w, r, request); !ok {
-	// 	return
-	// }
+	if ok := c.DecodeAndValidate(w, r, request); !ok {
+		return
+	}
 
-	// cluster, err := getClusterModelFromManualRequest(c.Repo(), proj, request)
+	// get the AWS integration
+	awsInt, err := c.Repo().AWSIntegration().ReadAWSIntegration(proj.ID, request.AWSIntegrationID)
 
-	// if err != nil {
-	// 	c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
-	// 	return
-	// }
+	if err != nil {
+		if err == gorm.ErrRecordNotFound {
+			c.HandleAPIError(w, r, apierrors.NewErrForbidden(err))
+		} else {
+			c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+		}
 
-	// cluster, err = c.Repo().Cluster().CreateCluster(cluster)
+		return
+	}
 
-	// if err != nil {
-	// 	c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
-	// 	return
-	// }
+	suffix, err := repository.GenerateRandomBytes(6)
 
-	// c.WriteResult(w, r, cluster.ToClusterType())
-}
+	if err != nil {
+		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+		return
+	}
+
+	infra := &models.Infra{
+		Kind:             types.InfraECR,
+		ProjectID:        proj.ID,
+		Suffix:           suffix,
+		Status:           types.StatusCreating,
+		AWSIntegrationID: request.AWSIntegrationID,
+	}
 
-// HandleProvisionAWSECRInfra provisions a new aws ECR instance for a project
-// func (app *App) HandleProvisionAWSECRInfra(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
-// 	}
-
-// 	form := &forms.CreateECRInfra{
-// 		ProjectID: uint(projID),
-// 	}
-
-// 	// decode from JSON to form value
-// 	if err := json.NewDecoder(r.Body).Decode(form); err != nil {
-// 		app.handleErrorFormDecoding(err, ErrProjectDecode, w)
-// 		return
-// 	}
-
-// 	// validate the form
-// 	if err := app.validator.Struct(form); err != nil {
-// 		app.handleErrorFormValidation(err, ErrProjectValidateFields, w)
-// 		return
-// 	}
-
-// 	// convert the form to an aws infra instance
-// 	infra, err := form.ToInfra()
-
-// 	if err != nil {
-// 		app.handleErrorFormDecoding(err, ErrProjectDecode, w)
-// 		return
-// 	}
-
-// 	// handle write to the database
-// 	infra, err = app.Repo.Infra().CreateInfra(infra)
-
-// 	if err != nil {
-// 		app.handleErrorDataWrite(err, w)
-// 		return
-// 	}
-
-// 	awsInt, err := app.Repo.AWSIntegration().ReadAWSIntegration(infra.AWSIntegrationID)
-
-// 	if err != nil {
-// 		infra.Status = types.StatusError
-// 		infra, _ = app.Repo.Infra().UpdateInfra(infra)
-
-// 		app.handleErrorDataRead(err, w)
-// 		return
-// 	}
-
-// 	// launch provisioning pod
-// 	_, err = app.ProvisionerAgent.ProvisionECR(
-// 		uint(projID),
-// 		awsInt,
-// 		form.ECRName,
-// 		app.Repo,
-// 		infra,
-// 		provisioner.Apply,
-// 		&app.DBConf,
-// 		app.RedisConf,
-// 		app.ServerConf.ProvisionerImageTag,
-// 		app.ServerConf.ProvisionerImagePullSecret,
-// 	)
-
-// 	if err != nil {
-// 		infra.Status = types.StatusError
-// 		infra, _ = app.Repo.Infra().UpdateInfra(infra)
-
-// 		app.handleErrorInternal(err, w)
-// 		return
-// 	}
-
-// 	app.Logger.Info().Msgf("New aws ecr infra created: %d", infra.ID)
-
-// 	w.WriteHeader(http.StatusCreated)
-
-// 	infraExt := infra.ToInfraType()
-
-// 	if err := json.NewEncoder(w).Encode(infraExt); err != nil {
-// 		app.handleErrorFormDecoding(err, ErrProjectDecode, w)
-// 		return
-// 	}
-// }
+	// handle write to the database
+	infra, err = c.Repo().Infra().CreateInfra(infra)
+
+	if err != nil {
+		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+		return
+	}
+
+	// launch provisioning pod
+	_, err = c.Config().ProvisionerAgent.ProvisionECR(
+		&kubernetes.SharedProvisionOpts{
+			ProjectID:           proj.ID,
+			Repo:                c.Repo(),
+			Infra:               infra,
+			Operation:           provisioner.Apply,
+			PGConf:              c.Config().DBConf,
+			RedisConf:           c.Config().RedisConf,
+			ProvImageTag:        c.Config().ServerConf.ProvisionerImageTag,
+			ProvImagePullSecret: c.Config().ServerConf.ProvisionerImagePullSecret,
+		},
+		awsInt,
+		request.ECRName,
+	)
+
+	if err != nil {
+		infra.Status = types.StatusError
+		infra, _ = c.Repo().Infra().UpdateInfra(infra)
+		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+		return
+	}
+
+	c.WriteResult(w, r, infra.ToInfraType())
+}

+ 199 - 0
api/server/handlers/provision/provision_eks.go

@@ -0,0 +1,199 @@
+package provision
+
+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/kubernetes"
+	"github.com/porter-dev/porter/internal/kubernetes/provisioner"
+	"github.com/porter-dev/porter/internal/models"
+	"github.com/porter-dev/porter/internal/repository"
+	"gorm.io/gorm"
+)
+
+type ProvisionEKSHandler struct {
+	handlers.PorterHandlerReadWriter
+}
+
+func NewProvisionEKSHandler(
+	config *config.Config,
+	decoderValidator shared.RequestDecoderValidator,
+	writer shared.ResultWriter,
+) *ProvisionEKSHandler {
+	return &ProvisionEKSHandler{
+		PorterHandlerReadWriter: handlers.NewDefaultPorterHandler(config, decoderValidator, writer),
+	}
+}
+
+func (c *ProvisionEKSHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+	// read the project from context
+	proj, _ := r.Context().Value(types.ProjectScope).(*models.Project)
+
+	request := &types.CreateEKSInfraRequest{}
+
+	if ok := c.DecodeAndValidate(w, r, request); !ok {
+		return
+	}
+
+	// get the AWS integration
+	awsInt, err := c.Repo().AWSIntegration().ReadAWSIntegration(proj.ID, request.AWSIntegrationID)
+
+	if err != nil {
+		if err == gorm.ErrRecordNotFound {
+			c.HandleAPIError(w, r, apierrors.NewErrForbidden(err))
+		} else {
+			c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+		}
+
+		return
+	}
+
+	suffix, err := repository.GenerateRandomBytes(6)
+
+	if err != nil {
+		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+		return
+	}
+
+	infra := &models.Infra{
+		Kind:             types.InfraEKS,
+		ProjectID:        proj.ID,
+		Suffix:           suffix,
+		Status:           types.StatusCreating,
+		AWSIntegrationID: request.AWSIntegrationID,
+	}
+
+	// handle write to the database
+	infra, err = c.Repo().Infra().CreateInfra(infra)
+
+	if err != nil {
+		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+		return
+	}
+
+	// launch provisioning pod
+	_, err = c.Config().ProvisionerAgent.ProvisionEKS(
+		&kubernetes.SharedProvisionOpts{
+			ProjectID:           proj.ID,
+			Repo:                c.Repo(),
+			Infra:               infra,
+			Operation:           provisioner.Apply,
+			PGConf:              c.Config().DBConf,
+			RedisConf:           c.Config().RedisConf,
+			ProvImageTag:        c.Config().ServerConf.ProvisionerImageTag,
+			ProvImagePullSecret: c.Config().ServerConf.ProvisionerImagePullSecret,
+		},
+		awsInt,
+		request.EKSName,
+		request.MachineType,
+	)
+
+	if err != nil {
+		infra.Status = types.StatusError
+		infra, _ = c.Repo().Infra().UpdateInfra(infra)
+		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+		return
+	}
+
+	c.WriteResult(w, r, infra.ToInfraType())
+}
+
+// // HandleProvisionAWSEKSInfra provisions a new aws EKS instance for a project
+// func (app *App) HandleProvisionAWSEKSInfra(w http.ResponseWriter, r *http.Request) {
+// 	projID, err := strconv.ParseUint(chi.URLParam(r, "project_id"), 0, 64)
+// 	userID, err := app.getUserIDFromRequest(r)
+
+// 	if err != nil || projID == 0 {
+// 		app.handleErrorFormDecoding(err, ErrProjectDecode, w)
+// 		return
+// 	}
+
+// 	form := &forms.CreateEKSInfra{
+// 		ProjectID: uint(projID),
+// 	}
+
+// 	// decode from JSON to form value
+// 	if err := json.NewDecoder(r.Body).Decode(form); err != nil {
+// 		app.handleErrorFormDecoding(err, ErrProjectDecode, w)
+// 		return
+// 	}
+
+// 	// validate the form
+// 	if err := app.validator.Struct(form); err != nil {
+// 		app.handleErrorFormValidation(err, ErrProjectValidateFields, w)
+// 		return
+// 	}
+
+// 	// convert the form to an aws infra instance
+// 	infra, err := form.ToInfra()
+
+// 	if err != nil {
+// 		app.handleErrorFormDecoding(err, ErrProjectDecode, w)
+// 		return
+// 	}
+
+// 	// handle write to the database
+// 	infra, err = app.Repo.Infra().CreateInfra(infra)
+
+// 	if err != nil {
+// 		app.handleErrorDataWrite(err, w)
+// 		return
+// 	}
+
+// 	awsInt, err := app.Repo.AWSIntegration().ReadAWSIntegration(infra.AWSIntegrationID)
+
+// 	if err != nil {
+// 		infra.Status = types.StatusError
+// 		infra, _ = app.Repo.Infra().UpdateInfra(infra)
+
+// 		app.handleErrorDataRead(err, w)
+// 		return
+// 	}
+
+// 	// launch provisioning pod
+// 	_, err = app.ProvisionerAgent.ProvisionEKS(
+// 		uint(projID),
+// 		awsInt,
+// 		form.EKSName,
+// 		form.MachineType,
+// 		app.Repo,
+// 		infra,
+// 		provisioner.Apply,
+// 		&app.DBConf,
+// 		app.RedisConf,
+// 		app.ServerConf.ProvisionerImageTag,
+// 		app.ServerConf.ProvisionerImagePullSecret,
+// 	)
+
+// 	if err != nil {
+// 		infra.Status = types.StatusError
+// 		infra, _ = app.Repo.Infra().UpdateInfra(infra)
+
+// 		app.handleErrorInternal(err, w)
+// 		return
+// 	}
+
+// 	app.Logger.Info().Msgf("New aws eks infra created: %d", infra.ID)
+// 	app.analyticsClient.Track(analytics.CreateSegmentNewClusterEvent(
+// 		&analytics.NewClusterEventOpts{
+// 			UserId:      fmt.Sprintf("%d", userID),
+// 			ProjId:      fmt.Sprintf("%d", infra.ProjectID),
+// 			ClusterName: form.EKSName,
+// 			ClusterType: "EKS",
+// 			EventType:   "provisioned",
+// 		},
+// 	))
+
+// 	w.WriteHeader(http.StatusCreated)
+
+// 	infraExt := infra.ToInfraType()
+
+// 	if err := json.NewEncoder(w).Encode(infraExt); err != nil {
+// 		app.handleErrorFormDecoding(err, ErrProjectDecode, w)
+// 		return
+// 	}
+// }

+ 57 - 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/provision"
 	"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"
@@ -357,5 +358,61 @@ func getProjectRoutes(
 		Router:   r,
 	})
 
+	//  POST /api/projects/{project_id}/provision/ecr -> provision.NewProvisionECRHandler
+	provisionECREndpoint := factory.NewAPIEndpoint(
+		&types.APIRequestMetadata{
+			Verb:   types.APIVerbCreate,
+			Method: types.HTTPVerbPost,
+			Path: &types.Path{
+				Parent:       basePath,
+				RelativePath: relPath + "/provision/ecr",
+			},
+			Scopes: []types.PermissionScope{
+				types.UserScope,
+				types.ProjectScope,
+			},
+		},
+	)
+
+	provisionECRHandler := provision.NewProvisionECRHandler(
+		config,
+		factory.GetDecoderValidator(),
+		factory.GetResultWriter(),
+	)
+
+	routes = append(routes, &Route{
+		Endpoint: provisionECREndpoint,
+		Handler:  provisionECRHandler,
+		Router:   r,
+	})
+
+	//  POST /api/projects/{project_id}/provision/eks -> provision.NewProvisionEKSHandler
+	provisionEKSEndpoint := factory.NewAPIEndpoint(
+		&types.APIRequestMetadata{
+			Verb:   types.APIVerbCreate,
+			Method: types.HTTPVerbPost,
+			Path: &types.Path{
+				Parent:       basePath,
+				RelativePath: relPath + "/provision/eks",
+			},
+			Scopes: []types.PermissionScope{
+				types.UserScope,
+				types.ProjectScope,
+			},
+		},
+	)
+
+	provisionEKSHandler := provision.NewProvisionEKSHandler(
+		config,
+		factory.GetDecoderValidator(),
+		factory.GetResultWriter(),
+	)
+
+	routes = append(routes, &Route{
+		Endpoint: provisionEKSEndpoint,
+		Handler:  provisionEKSHandler,
+		Router:   r,
+	})
+
 	return routes, newPath
 }

+ 6 - 0
api/server/shared/config/config.go

@@ -36,6 +36,12 @@ type Config struct {
 	// ServerConf is the set of configuration variables for the Porter server
 	ServerConf *env.ServerConf
 
+	// DBConf is the set of configuration variables for the DB
+	DBConf *env.DBConf
+
+	// RedisConf is the set of configuration variables for the redis instance
+	RedisConf *env.RedisConf
+
 	// TokenConf contains the config for generating and validating JWT tokens
 	TokenConf *token.TokenGeneratorConf
 

+ 2 - 0
api/server/shared/config/loader/loader.go

@@ -41,6 +41,8 @@ func (e *EnvConfigLoader) LoadConfig() (res *config.Config, err error) {
 	res = &config.Config{
 		Logger:     lr.NewConsole(sc.Debug),
 		ServerConf: sc,
+		DBConf:     envConf.DBConf,
+		RedisConf:  envConf.RedisConf,
 	}
 
 	res.Metadata = config.MetadataFromConf(envConf.ServerConf)

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

@@ -106,8 +106,8 @@
 | <li>- [x] `GET /api/projects/{project_id}/policy`                                                                           | AS          |                 |             | yes              |
 | <li>- [ ] `POST /api/projects/{project_id}/provision/docr`                                                                  |             |                 |             |                  |
 | <li>- [ ] `POST /api/projects/{project_id}/provision/doks`                                                                  |             |                 |             |                  |
-| <li>- [ ] `POST /api/projects/{project_id}/provision/ecr`                                                                   |             |                 |             |                  |
-| <li>- [ ] `POST /api/projects/{project_id}/provision/eks`                                                                   |             |                 |             |                  |
+| <li>- [X] `POST /api/projects/{project_id}/provision/ecr`                                                                   | AB          |                 |             |                  |
+| <li>- [X] `POST /api/projects/{project_id}/provision/eks`                                                                   | AB          |                 |             |                  |
 | <li>- [ ] `POST /api/projects/{project_id}/provision/gcr`                                                                   |             |                 |             |                  |
 | <li>- [ ] `POST /api/projects/{project_id}/provision/gke`                                                                   |             |                 |             |                  |
 | <li>- [ ] `POST /api/projects/{project_id}/provision/test`                                                                  |             |                 |             |                  |