2
0
Эх сурвалжийг харах

added destruction handlers

Alexander Belanger 5 жил өмнө
parent
commit
68788ab09c

+ 12 - 0
internal/forms/infra.go

@@ -44,3 +44,15 @@ func (ce *CreateEKSInfra) ToAWSInfra() (*models.AWSInfra, error) {
 		AWSIntegrationID: ce.AWSIntegrationID,
 	}, nil
 }
+
+// DestroyECRInfra represents the accepted values for destroying an
+// ECR infra via the provisioning container
+type DestroyECRInfra struct {
+	ECRName string `json:"ecr_name" form:"required"`
+}
+
+// DestroyEKSInfra represents the accepted values for destroying an
+// EKS infra via the provisioning container
+type DestroyEKSInfra struct {
+	EKSName string `json:"eks_name" form:"required"`
+}

+ 15 - 9
internal/kubernetes/agent.go

@@ -239,12 +239,14 @@ func (a *Agent) ProvisionECR(
 	awsConf *integrations.AWSIntegration,
 	ecrName string,
 	awsInfra *models.AWSInfra,
+	operation provisioner.ProvisionerOperation,
 ) (*batchv1.Job, error) {
 	id := awsInfra.GetID()
 	prov := &provisioner.Conf{
-		ID:   id,
-		Name: fmt.Sprintf("prov-%s", id),
-		Kind: provisioner.ECR,
+		ID:        id,
+		Name:      fmt.Sprintf("prov-%s-%s", id, string(operation)),
+		Kind:      provisioner.ECR,
+		Operation: operation,
 		AWS: &aws.Conf{
 			AWSRegion:          awsConf.AWSRegion,
 			AWSAccessKeyID:     string(awsConf.AWSAccessKeyID),
@@ -264,12 +266,14 @@ func (a *Agent) ProvisionEKS(
 	awsConf *integrations.AWSIntegration,
 	eksName string,
 	awsInfra *models.AWSInfra,
+	operation provisioner.ProvisionerOperation,
 ) (*batchv1.Job, error) {
 	id := awsInfra.GetID()
 	prov := &provisioner.Conf{
-		ID:   id,
-		Name: fmt.Sprintf("prov-%s", id),
-		Kind: provisioner.EKS,
+		ID:        id,
+		Name:      fmt.Sprintf("prov-%s-%s", id, string(operation)),
+		Kind:      provisioner.EKS,
+		Operation: provisioner.Apply,
 		AWS: &aws.Conf{
 			AWSRegion:          awsConf.AWSRegion,
 			AWSAccessKeyID:     string(awsConf.AWSAccessKeyID),
@@ -286,11 +290,13 @@ func (a *Agent) ProvisionEKS(
 // ProvisionTest spawns a new provisioning pod that tests provisioning
 func (a *Agent) ProvisionTest(
 	projectID uint,
+	operation provisioner.ProvisionerOperation,
 ) (*batchv1.Job, error) {
 	prov := &provisioner.Conf{
-		ID:   fmt.Sprintf("%s-%d", "testing", projectID),
-		Name: fmt.Sprintf("prov-%s-%d", "testing", projectID),
-		Kind: provisioner.Test,
+		ID:        fmt.Sprintf("%s-%d", "testing", projectID),
+		Name:      fmt.Sprintf("prov-%s-%d-%s", "testing", projectID, string(operation)),
+		Operation: provisioner.Apply,
+		Kind:      provisioner.Test,
 	}
 
 	return a.provision(prov)

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

@@ -214,6 +214,20 @@ func GlobalStreamListener(
 
 				infra, err = repo.AWSInfra.UpdateAWSInfra(infra)
 
+				if err != nil {
+					continue
+				}
+			} else if fmt.Sprintf("%v", msg.Values["status"]) == "destroyed" {
+				infra, err := repo.AWSInfra.ReadAWSInfra(infraID)
+
+				if err != nil {
+					continue
+				}
+
+				infra.Status = models.StatusDestroyed
+
+				infra, err = repo.AWSInfra.UpdateAWSInfra(infra)
+
 				if err != nil {
 					continue
 				}

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

@@ -30,6 +30,7 @@ type Conf struct {
 	ID        string
 	Redis     *config.RedisConf
 	Postgres  *PostgresConf
+	Operation ProvisionerOperation
 
 	// provider-specific configurations
 	AWS *aws.Conf
@@ -43,9 +44,22 @@ type PostgresConf struct {
 	Port string
 }
 
+type ProvisionerOperation string
+
+const (
+	Apply   ProvisionerOperation = "apply"
+	Destroy ProvisionerOperation = "destroy"
+)
+
 // GetProvisionerJobTemplate returns the manifest that should be applied to
 // create a provisioning job
 func (conf *Conf) GetProvisionerJobTemplate() (*batchv1.Job, error) {
+	operation := string(conf.Operation)
+
+	if conf.Operation == "" {
+		operation = string(Apply)
+	}
+
 	env := make([]v1.EnvVar, 0)
 
 	env = conf.attachDefaultEnv(env)
@@ -60,13 +74,13 @@ func (conf *Conf) GetProvisionerJobTemplate() (*batchv1.Job, error) {
 	args := make([]string, 0)
 
 	if conf.Kind == Test {
-		args = []string{"test", "hello"}
+		args = []string{operation, "test", "hello"}
 	} else if conf.Kind == ECR {
-		args = []string{"apply", "ecr"}
+		args = []string{operation, "ecr"}
 		env = conf.AWS.AttachAWSEnv(env)
 		env = conf.ECR.AttachECREnv(env)
 	} else if conf.Kind == EKS {
-		args = []string{"apply", "eks"}
+		args = []string{operation, "eks"}
 		env = conf.AWS.AttachAWSEnv(env)
 		env = conf.EKS.AttachEKSEnv(env)
 	}

+ 142 - 1
server/api/provision_handler.go

@@ -10,6 +10,7 @@ import (
 	"github.com/porter-dev/porter/internal/forms"
 	"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/adapter"
 )
@@ -32,7 +33,7 @@ func (app *App) HandleProvisionTest(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 
-	_, err = agent.ProvisionTest(uint(projID))
+	_, err = agent.ProvisionTest(uint(projID), provisioner.Apply)
 
 	if err != nil {
 		app.handleErrorInternal(err, w)
@@ -103,6 +104,7 @@ func (app *App) HandleProvisionAWSECRInfra(w http.ResponseWriter, r *http.Reques
 		awsInt,
 		form.ECRName,
 		infra,
+		provisioner.Apply,
 	)
 
 	if err != nil {
@@ -122,6 +124,75 @@ func (app *App) HandleProvisionAWSECRInfra(w http.ResponseWriter, r *http.Reques
 	}
 }
 
+// HandleDestroyAWSECRInfra destroys ecr infra
+func (app *App) HandleDestroyAWSECRInfra(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.AWSInfra.ReadAWSInfra(uint(infraID))
+
+	if err != nil {
+		app.handleErrorDataRead(err, w)
+		return
+	}
+
+	awsInt, err := app.Repo.AWSIntegration.ReadAWSIntegration(infra.AWSIntegrationID)
+
+	form := &forms.DestroyECRInfra{}
+
+	// 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
+	}
+
+	// launch provisioning destruction pod
+	agent, err := kubernetes.GetAgentInClusterConfig()
+
+	if err != nil {
+		app.handleErrorDataRead(err, w)
+		return
+	}
+
+	// mark infra for deletion
+	infra.Status = models.StatusDestroying
+	infra, err = app.Repo.AWSInfra.UpdateAWSInfra(infra)
+
+	if err != nil {
+		app.handleErrorDataWrite(err, w)
+		return
+	}
+
+	_, err = agent.ProvisionECR(
+		infra.ProjectID,
+		awsInt,
+		form.ECRName,
+		infra,
+		provisioner.Destroy,
+	)
+
+	if err != nil {
+		app.handleErrorInternal(err, w)
+		return
+	}
+
+	app.Logger.Info().Msgf("AWS ECR infra marked for destruction: %d", infra.ID)
+
+	w.WriteHeader(http.StatusOK)
+}
+
 // 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)
@@ -183,6 +254,7 @@ func (app *App) HandleProvisionAWSEKSInfra(w http.ResponseWriter, r *http.Reques
 		awsInt,
 		form.EKSName,
 		infra,
+		provisioner.Apply,
 	)
 
 	if err != nil {
@@ -202,6 +274,75 @@ func (app *App) HandleProvisionAWSEKSInfra(w http.ResponseWriter, r *http.Reques
 	}
 }
 
+// HandleDestroyAWSEKSInfra destroys eks infra
+func (app *App) HandleDestroyAWSEKSInfra(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.AWSInfra.ReadAWSInfra(uint(infraID))
+
+	if err != nil {
+		app.handleErrorDataRead(err, w)
+		return
+	}
+
+	awsInt, err := app.Repo.AWSIntegration.ReadAWSIntegration(infra.AWSIntegrationID)
+
+	form := &forms.DestroyEKSInfra{}
+
+	// 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
+	}
+
+	// launch provisioning destruction pod
+	agent, err := kubernetes.GetAgentInClusterConfig()
+
+	if err != nil {
+		app.handleErrorDataRead(err, w)
+		return
+	}
+
+	// mark infra for deletion
+	infra.Status = models.StatusDestroying
+	infra, err = app.Repo.AWSInfra.UpdateAWSInfra(infra)
+
+	if err != nil {
+		app.handleErrorDataWrite(err, w)
+		return
+	}
+
+	_, err = agent.ProvisionEKS(
+		infra.ProjectID,
+		awsInt,
+		form.EKSName,
+		infra,
+		provisioner.Destroy,
+	)
+
+	if err != nil {
+		app.handleErrorInternal(err, w)
+		return
+	}
+
+	app.Logger.Info().Msgf("AWS EKS infra marked for destruction: %d", infra.ID)
+
+	w.WriteHeader(http.StatusOK)
+}
+
 // HandleGetProvisioningLogs returns real-time logs of the provisioning process via websockets
 func (app *App) HandleGetProvisioningLogs(w http.ResponseWriter, r *http.Request) {
 	// get path parameters