Browse Source

Merge branch 'beta.3.dev-provisioner' of https://github.com/porter-dev/porter into sean-testing

Sean Rhee 5 years ago
parent
commit
3a920ea343

+ 38 - 0
docker/nginx_remote.conf

@@ -0,0 +1,38 @@
+events {}
+http {
+    upstream api {
+        server localhost:8081;
+    }
+
+    upstream webpack {
+        server localhost:8082;
+    }
+
+    server {
+        listen 8080;
+        server_name localhost;
+
+        location /api/ {
+            proxy_pass http://api;
+            proxy_http_version 1.1;
+            proxy_set_header Upgrade $http_upgrade;
+            proxy_set_header Connection 'upgrade';
+            proxy_set_header Host $host;
+            proxy_cache_bypass $http_upgrade;
+            proxy_set_header   X-Forwarded-Host $server_name;
+        }
+
+        location / {
+            proxy_pass http://webpack;
+            proxy_pass_header Content-Security-Policy;
+            proxy_http_version 1.1;
+            proxy_set_header Upgrade $http_upgrade;
+            proxy_set_header Connection 'upgrade';
+            proxy_set_header Host $host;
+            proxy_cache_bypass $http_upgrade;
+            proxy_set_header   X-Forwarded-Host $server_name;
+        }
+    }
+
+    client_max_body_size 10M;
+}

+ 1 - 1
internal/config/config.go

@@ -36,7 +36,7 @@ type ServerConf struct {
 
 	DOClientID          string `env:"DO_CLIENT_ID"`
 	DOClientSecret      string `env:"DO_CLIENT_SECRET"`
-	ProvisionerImageTag string `env:"PROV_IMAGE_TAG,default-latest"`
+	ProvisionerImageTag string `env:"PROV_IMAGE_TAG,default=latest"`
 }
 
 // DBConf is the database configuration: if generated from environment variables,

+ 16 - 0
internal/forms/infra.go

@@ -9,6 +9,22 @@ import (
 
 const randCharset string = "abcdefghijklmnopqrstuvwxyz1234567890"
 
+// CreateTestInfra represents the accepted values for creating test
+// infra via the provisioning container
+type CreateTestInfra struct {
+	ProjectID uint `json:"project_id" form:"required"`
+}
+
+// ToInfra converts the form to a gorm aws infra model
+func (ce *CreateTestInfra) ToInfra() (*models.Infra, error) {
+	return &models.Infra{
+		Kind:      models.InfraTest,
+		ProjectID: ce.ProjectID,
+		Suffix:    stringWithCharset(6, randCharset),
+		Status:    models.StatusCreating,
+	}, nil
+}
+
 // CreateECRInfra represents the accepted values for creating an
 // ECR infra via the provisioning container
 type CreateECRInfra struct {

+ 43 - 14
internal/kubernetes/agent.go

@@ -393,6 +393,7 @@ func (a *Agent) ProvisionDOCR(
 	operation provisioner.ProvisionerOperation,
 	pgConf *config.DBConf,
 	redisConf *config.RedisConf,
+	provImageTag string,
 ) (*batchv1.Job, error) {
 	// get the token
 	oauthInt, err := repo.OAuthIntegration.ReadOAuthIntegration(
@@ -411,13 +412,14 @@ func (a *Agent) ProvisionDOCR(
 
 	id := infra.GetUniqueName()
 	prov := &provisioner.Conf{
-		ID:          id,
-		Name:        fmt.Sprintf("prov-%s-%s", id, string(operation)),
-		Kind:        provisioner.DOCR,
-		Operation:   operation,
-		Redis:       redisConf,
-		Postgres:    pgConf,
-		LastApplied: infra.LastApplied,
+		ID:                  id,
+		Name:                fmt.Sprintf("prov-%s-%s", id, string(operation)),
+		Kind:                provisioner.DOCR,
+		Operation:           operation,
+		Redis:               redisConf,
+		Postgres:            pgConf,
+		ProvisionerImageTag: provImageTag,
+		LastApplied:         infra.LastApplied,
 		DO: &do.Conf{
 			DOToken: tok,
 		},
@@ -441,6 +443,7 @@ func (a *Agent) ProvisionDOKS(
 	operation provisioner.ProvisionerOperation,
 	pgConf *config.DBConf,
 	redisConf *config.RedisConf,
+	provImageTag string,
 ) (*batchv1.Job, error) {
 	// get the token
 	oauthInt, err := repo.OAuthIntegration.ReadOAuthIntegration(
@@ -459,13 +462,14 @@ func (a *Agent) ProvisionDOKS(
 
 	id := infra.GetUniqueName()
 	prov := &provisioner.Conf{
-		ID:          id,
-		Name:        fmt.Sprintf("prov-%s-%s", id, string(operation)),
-		Kind:        provisioner.DOKS,
-		Operation:   operation,
-		Redis:       redisConf,
-		Postgres:    pgConf,
-		LastApplied: infra.LastApplied,
+		ID:                  id,
+		Name:                fmt.Sprintf("prov-%s-%s", id, string(operation)),
+		Kind:                provisioner.DOKS,
+		Operation:           operation,
+		Redis:               redisConf,
+		Postgres:            pgConf,
+		LastApplied:         infra.LastApplied,
+		ProvisionerImageTag: provImageTag,
 		DO: &do.Conf{
 			DOToken: tok,
 		},
@@ -478,6 +482,31 @@ func (a *Agent) ProvisionDOKS(
 	return a.provision(prov, infra, repo)
 }
 
+// ProvisionTest spawns a new provisioning pod that tests provisioning
+func (a *Agent) ProvisionTest(
+	projectID uint,
+	infra *models.Infra,
+	repo repository.Repository,
+	operation provisioner.ProvisionerOperation,
+	pgConf *config.DBConf,
+	redisConf *config.RedisConf,
+	provImageTag string,
+) (*batchv1.Job, error) {
+	id := infra.GetUniqueName()
+
+	prov := &provisioner.Conf{
+		ID:                  id,
+		Name:                fmt.Sprintf("prov-%s-%s", id, string(operation)),
+		Operation:           operation,
+		Kind:                provisioner.Test,
+		Redis:               redisConf,
+		Postgres:            pgConf,
+		ProvisionerImageTag: provImageTag,
+	}
+
+	return a.provision(prov, infra, repo)
+}
+
 func (a *Agent) provision(
 	prov *provisioner.Conf,
 	infra *models.Infra,

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

@@ -26,6 +26,7 @@ type InfraOption string
 
 // The list of infra options
 const (
+	Test InfraOption = "test"
 	ECR  InfraOption = "ecr"
 	EKS  InfraOption = "eks"
 	GCR  InfraOption = "gcr"
@@ -94,6 +95,8 @@ func (conf *Conf) GetProvisionerJobTemplate() (*batchv1.Job, error) {
 	args := make([]string, 0)
 
 	switch conf.Kind {
+	case Test:
+		args = []string{operation, "test", "hello"}
 	case ECR:
 		args = []string{operation, "ecr"}
 

+ 1 - 0
internal/models/infra.go

@@ -25,6 +25,7 @@ type InfraKind string
 
 // The supported infra kinds
 const (
+	InfraTest InfraKind = "test"
 	InfraECR  InfraKind = "ecr"
 	InfraEKS  InfraKind = "eks"
 	InfraGCR  InfraKind = "gcr"

+ 136 - 0
server/api/provision_handler.go

@@ -15,6 +15,138 @@ import (
 	"github.com/porter-dev/porter/internal/adapter"
 )
 
+// HandleProvisionTestInfra will create a test resource by deploying a provisioner
+// container pod
+func (app *App) HandleProvisionTestInfra(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
+	}
+
+	// create a new agent
+	agent, err := kubernetes.GetAgentInClusterConfig()
+
+	if err != nil {
+		app.handleErrorDataRead(err, w)
+		return
+	}
+
+	form := &forms.CreateTestInfra{
+		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
+	}
+
+	// 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
+	}
+
+	_, err = agent.ProvisionTest(
+		uint(projID),
+		infra,
+		*app.Repo,
+		provisioner.Apply,
+		&app.DBConf,
+		app.RedisConf,
+		app.ServerConf.ProvisionerImageTag,
+	)
+
+	if err != nil {
+		infra.Status = models.StatusError
+		infra, _ = app.Repo.Infra.UpdateInfra(infra)
+
+		app.handleErrorInternal(err, w)
+		return
+	}
+
+	app.Logger.Info().Msgf("New test 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
+	}
+}
+
+// HandleDestroyTestInfra destroys test infra
+func (app *App) HandleDestroyTestInfra(w http.ResponseWriter, r *http.Request) {
+	// get path parameters
+	infraID, err := strconv.ParseUint(chi.URLParam(r, "infra_id"), 10, 64)
+
+	if err != nil {
+		app.handleErrorFormDecoding(err, ErrProjectDecode, w)
+		return
+	}
+
+	// read infra to get id
+	infra, err := app.Repo.Infra.ReadInfra(uint(infraID))
+
+	if err != nil {
+		app.handleErrorDataRead(err, w)
+		return
+	}
+
+	// launch provisioning destruction pod
+	agent, err := kubernetes.GetAgentInClusterConfig()
+
+	if err != nil {
+		infra.Status = models.StatusError
+		infra, _ = app.Repo.Infra.UpdateInfra(infra)
+
+		app.handleErrorDataRead(err, w)
+		return
+	}
+
+	// mark infra for deletion
+	infra.Status = models.StatusDestroying
+	infra, err = app.Repo.Infra.UpdateInfra(infra)
+
+	if err != nil {
+		app.handleErrorDataWrite(err, w)
+		return
+	}
+
+	_, err = agent.ProvisionTest(
+		infra.ProjectID,
+		infra,
+		*app.Repo,
+		provisioner.Destroy,
+		&app.DBConf,
+		app.RedisConf,
+		app.ServerConf.ProvisionerImageTag,
+	)
+
+	if err != nil {
+		app.handleErrorInternal(err, w)
+		return
+	}
+
+	app.Logger.Info().Msgf("Test infra marked for destruction: %d", infra.ID)
+
+	w.WriteHeader(http.StatusOK)
+}
+
 // 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)
@@ -753,6 +885,7 @@ func (app *App) HandleProvisionDODOCRInfra(w http.ResponseWriter, r *http.Reques
 		provisioner.Apply,
 		&app.DBConf,
 		app.RedisConf,
+		app.ServerConf.ProvisionerImageTag,
 	)
 
 	if err != nil {
@@ -846,6 +979,7 @@ func (app *App) HandleDestroyDODOCRInfra(w http.ResponseWriter, r *http.Request)
 		provisioner.Destroy,
 		&app.DBConf,
 		app.RedisConf,
+		app.ServerConf.ProvisionerImageTag,
 	)
 
 	if err != nil {
@@ -931,6 +1065,7 @@ func (app *App) HandleProvisionDODOKSInfra(w http.ResponseWriter, r *http.Reques
 		provisioner.Apply,
 		&app.DBConf,
 		app.RedisConf,
+		app.ServerConf.ProvisionerImageTag,
 	)
 
 	if err != nil {
@@ -1024,6 +1159,7 @@ func (app *App) HandleDestroyDODOKSInfra(w http.ResponseWriter, r *http.Request)
 		provisioner.Destroy,
 		&app.DBConf,
 		app.RedisConf,
+		app.ServerConf.ProvisionerImageTag,
 	)
 
 	if err != nil {

+ 24 - 0
server/router/router.go

@@ -248,6 +248,16 @@ func New(a *api.App) *chi.Mux {
 		)
 
 		// /api/projects/{project_id}/provision routes
+		r.Method(
+			"POST",
+			"/projects/{project_id}/provision/test",
+			auth.DoesUserHaveProjectAccess(
+				requestlog.NewHandler(a.HandleProvisionTestInfra, l),
+				mw.URLParam,
+				mw.ReadAccess,
+			),
+		)
+
 		r.Method(
 			"POST",
 			"/projects/{project_id}/provision/ecr",
@@ -380,6 +390,20 @@ func New(a *api.App) *chi.Mux {
 			),
 		)
 
+		r.Method(
+			"POST",
+			"/projects/{project_id}/infra/{infra_id}/test/destroy",
+			auth.DoesUserHaveProjectAccess(
+				auth.DoesUserHaveInfraAccess(
+					requestlog.NewHandler(a.HandleDestroyTestInfra, l),
+					mw.URLParam,
+					mw.URLParam,
+				),
+				mw.URLParam,
+				mw.ReadAccess,
+			),
+		)
+
 		r.Method(
 			"POST",
 			"/projects/{project_id}/infra/{infra_id}/eks/destroy",