Kaynağa Gözat

gcr provisioning

Alexander Belanger 5 yıl önce
ebeveyn
işleme
2b349b04cb

+ 18 - 0
internal/forms/infra.go

@@ -47,6 +47,24 @@ func (ce *CreateEKSInfra) ToAWSInfra() (*models.AWSInfra, error) {
 	}, nil
 }
 
+// CreateGCRInfra represents the accepted values for creating an
+// GCR infra via the provisioning container
+type CreateGCRInfra struct {
+	ProjectID        uint `json:"project_id" form:"required"`
+	GCPIntegrationID uint `json:"gcp_integration_id" form:"required"`
+}
+
+// ToAWSInfra converts the form to a gorm aws infra model
+func (ce *CreateGCRInfra) ToAWSInfra() (*models.AWSInfra, error) {
+	return &models.AWSInfra{
+		Kind:             models.AWSInfraGCR,
+		ProjectID:        ce.ProjectID,
+		Suffix:           stringWithCharset(6, randCharset),
+		Status:           models.StatusCreating,
+		GCPIntegrationID: ce.GCPIntegrationID,
+	}, nil
+}
+
 // DestroyECRInfra represents the accepted values for destroying an
 // ECR infra via the provisioning container
 type DestroyECRInfra struct {

+ 28 - 0
internal/kubernetes/agent.go

@@ -11,6 +11,7 @@ import (
 	"github.com/porter-dev/porter/internal/kubernetes/provisioner/aws"
 	"github.com/porter-dev/porter/internal/kubernetes/provisioner/aws/ecr"
 	"github.com/porter-dev/porter/internal/kubernetes/provisioner/aws/eks"
+	"github.com/porter-dev/porter/internal/kubernetes/provisioner/gcp"
 	"github.com/porter-dev/porter/internal/models"
 	"github.com/porter-dev/porter/internal/models/integrations"
 
@@ -296,6 +297,33 @@ func (a *Agent) ProvisionEKS(
 	return a.provision(prov)
 }
 
+// ProvisionGCR spawns a new provisioning pod that creates a GCR instance
+func (a *Agent) ProvisionGCR(
+	projectID uint,
+	gcpConf *integrations.GCPIntegration,
+	awsInfra *models.AWSInfra,
+	operation provisioner.ProvisionerOperation,
+	pgConf *config.DBConf,
+	redisConf *config.RedisConf,
+) (*batchv1.Job, error) {
+	id := awsInfra.GetID()
+	prov := &provisioner.Conf{
+		ID:        id,
+		Name:      fmt.Sprintf("prov-%s-%s", id, string(operation)),
+		Kind:      provisioner.GCR,
+		Operation: operation,
+		Redis:     redisConf,
+		Postgres:  pgConf,
+		GCP: &gcp.Conf{
+			GCPRegion:    gcpConf.GCPRegion,
+			GCPProjectID: gcpConf.GCPProjectID,
+			GCPKeyData:   string(gcpConf.GCPKeyData),
+		},
+	}
+
+	return a.provision(prov)
+}
+
 // ProvisionTest spawns a new provisioning pod that tests provisioning
 func (a *Agent) ProvisionTest(
 	projectID uint,

+ 20 - 0
internal/kubernetes/provisioner/global_stream.go

@@ -201,6 +201,26 @@ func GlobalStreamListener(
 
 					cluster, err := repo.Cluster.CreateCluster(cluster)
 
+					if err != nil {
+						continue
+					}
+				} else if kind == string(models.AWSInfraGCR) {
+					reg := &models.Registry{
+						ProjectID:        projID,
+						GCPIntegrationID: infra.GCPIntegrationID,
+						InfraID:          infra.ID,
+						Name:             "gcr-registry",
+					}
+
+					// parse raw data into ECR type
+					dataString, ok := msg.Values["data"].(string)
+
+					if ok {
+						json.Unmarshal([]byte(dataString), reg)
+					}
+
+					reg, err = repo.Registry.CreateRegistry(reg)
+
 					if err != nil {
 						continue
 					}

+ 3 - 0
internal/kubernetes/provisioner/provisioner.go

@@ -87,6 +87,9 @@ func (conf *Conf) GetProvisionerJobTemplate() (*batchv1.Job, error) {
 		args = []string{operation, "eks"}
 		env = conf.AWS.AttachAWSEnv(env)
 		env = conf.EKS.AttachEKSEnv(env)
+	} else if conf.Kind == GCR {
+		args = []string{operation, "gcr"}
+		env = conf.GCP.AttachGCPEnv(env)
 	}
 
 	return &batchv1.Job{

+ 4 - 0
internal/models/infra.go

@@ -27,6 +27,7 @@ type AWSInfraKind string
 const (
 	AWSInfraECR AWSInfraKind = "ecr"
 	AWSInfraEKS AWSInfraKind = "eks"
+	AWSInfraGCR AWSInfraKind = "gcr"
 )
 
 // AWSInfra represents the metadata for an infrastructure type provisioned on
@@ -48,6 +49,9 @@ type AWSInfra struct {
 
 	// The AWS integration that was used to create the infra
 	AWSIntegrationID uint
+
+	// The GCP integration that was used to create the infra
+	GCPIntegrationID uint
 }
 
 // AWSInfraExternal is an external AWSInfra to be shared over REST

+ 91 - 0
server/api/provision_handler.go

@@ -392,6 +392,97 @@ func (app *App) HandleDestroyAWSEKSInfra(w http.ResponseWriter, r *http.Request)
 	w.WriteHeader(http.StatusOK)
 }
 
+// HandleProvisionGCPGCRInfra enables GCR for a project
+func (app *App) HandleProvisionGCPGCRInfra(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.CreateGCRInfra{
+		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.ToAWSInfra()
+
+	if err != nil {
+		app.handleErrorFormDecoding(err, ErrProjectDecode, w)
+		return
+	}
+
+	// handle write to the database
+	infra, err = app.Repo.AWSInfra.CreateAWSInfra(infra)
+
+	if err != nil {
+		app.handleErrorDataWrite(err, w)
+		return
+	}
+
+	gcpInt, err := app.Repo.GCPIntegration.ReadGCPIntegration(infra.GCPIntegrationID)
+
+	if err != nil {
+		infra.Status = models.StatusError
+		infra, _ = app.Repo.AWSInfra.UpdateAWSInfra(infra)
+
+		app.handleErrorDataRead(err, w)
+		return
+	}
+
+	// launch provisioning pod
+	agent, err := kubernetes.GetAgentInClusterConfig()
+
+	if err != nil {
+		infra.Status = models.StatusError
+		infra, _ = app.Repo.AWSInfra.UpdateAWSInfra(infra)
+
+		app.handleErrorDataRead(err, w)
+		return
+	}
+
+	_, err = agent.ProvisionGCR(
+		uint(projID),
+		gcpInt,
+		infra,
+		provisioner.Apply,
+		&app.DBConf,
+		app.RedisConf,
+	)
+
+	if err != nil {
+		infra.Status = models.StatusError
+		infra, _ = app.Repo.AWSInfra.UpdateAWSInfra(infra)
+
+		app.handleErrorInternal(err, w)
+		return
+	}
+
+	app.Logger.Info().Msgf("New gcp gcr infra created: %d", infra.ID)
+
+	w.WriteHeader(http.StatusCreated)
+
+	infraExt := infra.Externalize()
+
+	if err := json.NewEncoder(w).Encode(infraExt); err != nil {
+		app.handleErrorFormDecoding(err, ErrProjectDecode, w)
+		return
+	}
+}
+
 // HandleGetProvisioningLogs returns real-time logs of the provisioning process via websockets
 func (app *App) HandleGetProvisioningLogs(w http.ResponseWriter, r *http.Request) {
 	// get path parameters

+ 15 - 0
server/router/router.go

@@ -229,6 +229,21 @@ func New(a *api.App) *chi.Mux {
 			),
 		)
 
+		r.Method(
+			"POST",
+			"/projects/{project_id}/provision/gcr",
+			auth.DoesUserHaveProjectAccess(
+				auth.DoesUserHaveGCPIntegrationAccess(
+					requestlog.NewHandler(a.HandleProvisionGCPGCRInfra, l),
+					mw.URLParam,
+					mw.BodyParam,
+					true,
+				),
+				mw.URLParam,
+				mw.ReadAccess,
+			),
+		)
+
 		r.Method(
 			"GET",
 			"/projects/{project_id}/provision/{kind}/{infra_id}/logs",