mirror of https://github.com/databricks/cli.git
Use apply mutator for bundle destroy
This commit is contained in:
parent
cd89e5b1ac
commit
42e4f283b5
|
@ -9,7 +9,16 @@ import (
|
|||
"github.com/hashicorp/terraform-exec/tfexec"
|
||||
)
|
||||
|
||||
type apply struct{}
|
||||
type ApplyGoal string
|
||||
|
||||
const (
|
||||
ApplyGoalDeploy = "deploy"
|
||||
ApplyGoalDestroy = "destroy"
|
||||
)
|
||||
|
||||
type apply struct {
|
||||
goal ApplyGoal
|
||||
}
|
||||
|
||||
func (w *apply) Name() string {
|
||||
return "terraform.Apply"
|
||||
|
@ -55,7 +64,12 @@ func (w *apply) Apply(ctx context.Context, b *bundle.Bundle) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
cmdio.LogString(ctx, "Starting deployment")
|
||||
switch w.goal {
|
||||
case ApplyGoalDeploy:
|
||||
cmdio.LogString(ctx, "Starting deployment")
|
||||
case ApplyGoalDestroy:
|
||||
cmdio.LogString(ctx, "Starting destruction")
|
||||
}
|
||||
|
||||
// Apply terraform according to the plan
|
||||
err = tf.Apply(ctx, tfexec.DirOrPlan(b.Plan.Path))
|
||||
|
@ -63,12 +77,18 @@ func (w *apply) Apply(ctx context.Context, b *bundle.Bundle) error {
|
|||
return fmt.Errorf("terraform apply: %w", err)
|
||||
}
|
||||
|
||||
cmdio.LogString(ctx, "Resource deployment completed!")
|
||||
switch w.goal {
|
||||
case ApplyGoalDeploy:
|
||||
cmdio.LogString(ctx, "Deployment Successful!")
|
||||
case ApplyGoalDestroy:
|
||||
cmdio.LogString(ctx, "Destruction Successful!")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Apply returns a [bundle.Mutator] that runs the equivalent of `terraform apply`
|
||||
// Apply returns a [bundle.Mutator] that runs the equivalent of `terraform apply ./plan`
|
||||
// from the bundle's ephemeral working directory for Terraform.
|
||||
func Apply() bundle.Mutator {
|
||||
return &apply{}
|
||||
func Apply(goal ApplyGoal) bundle.Mutator {
|
||||
return &apply{goal}
|
||||
}
|
||||
|
|
|
@ -1,123 +0,0 @@
|
|||
package terraform
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/databricks/cli/bundle"
|
||||
"github.com/databricks/cli/libs/cmdio"
|
||||
"github.com/fatih/color"
|
||||
"github.com/hashicorp/terraform-exec/tfexec"
|
||||
tfjson "github.com/hashicorp/terraform-json"
|
||||
)
|
||||
|
||||
type PlanResourceChange struct {
|
||||
ResourceType string `json:"resource_type"`
|
||||
Action string `json:"action"`
|
||||
ResourceName string `json:"resource_name"`
|
||||
}
|
||||
|
||||
func (c *PlanResourceChange) String() string {
|
||||
result := strings.Builder{}
|
||||
switch c.Action {
|
||||
case "delete":
|
||||
result.WriteString(" delete ")
|
||||
default:
|
||||
result.WriteString(c.Action + " ")
|
||||
}
|
||||
switch c.ResourceType {
|
||||
case "databricks_job":
|
||||
result.WriteString("job ")
|
||||
case "databricks_pipeline":
|
||||
result.WriteString("pipeline ")
|
||||
default:
|
||||
result.WriteString(c.ResourceType + " ")
|
||||
}
|
||||
result.WriteString(c.ResourceName)
|
||||
return result.String()
|
||||
}
|
||||
|
||||
func (c *PlanResourceChange) IsInplaceSupported() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func logDestroyPlan(ctx context.Context, changes []*tfjson.ResourceChange) error {
|
||||
cmdio.LogString(ctx, "The following resources will be removed:")
|
||||
for _, c := range changes {
|
||||
if c.Change.Actions.Delete() {
|
||||
cmdio.Log(ctx, &PlanResourceChange{
|
||||
ResourceType: c.Type,
|
||||
Action: "delete",
|
||||
ResourceName: c.Name,
|
||||
})
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type destroy struct{}
|
||||
|
||||
func (w *destroy) Name() string {
|
||||
return "terraform.Destroy"
|
||||
}
|
||||
|
||||
func (w *destroy) Apply(ctx context.Context, b *bundle.Bundle) error {
|
||||
// return early if plan is empty
|
||||
if b.Plan.IsEmpty {
|
||||
cmdio.LogString(ctx, "No resources to destroy in plan. Skipping destroy!")
|
||||
return nil
|
||||
}
|
||||
|
||||
tf := b.Terraform
|
||||
if tf == nil {
|
||||
return fmt.Errorf("terraform not initialized")
|
||||
}
|
||||
|
||||
// read plan file
|
||||
plan, err := tf.ShowPlanFile(ctx, b.Plan.Path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// print the resources that will be destroyed
|
||||
err = logDestroyPlan(ctx, plan.ResourceChanges)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Ask for confirmation, if needed
|
||||
if !b.Plan.ConfirmApply {
|
||||
red := color.New(color.FgRed).SprintFunc()
|
||||
b.Plan.ConfirmApply, err = cmdio.Ask(ctx, fmt.Sprintf("\nThis will permanently %s resources! Proceed? [y/n]: ", red("destroy")))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// return if confirmation was not provided
|
||||
if !b.Plan.ConfirmApply {
|
||||
return nil
|
||||
}
|
||||
|
||||
if b.Plan.Path == "" {
|
||||
return fmt.Errorf("no plan found")
|
||||
}
|
||||
|
||||
cmdio.LogString(ctx, "Starting to destroy resources")
|
||||
|
||||
// Apply terraform according to the computed destroy plan
|
||||
err = tf.Apply(ctx, tfexec.DirOrPlan(b.Plan.Path))
|
||||
if err != nil {
|
||||
return fmt.Errorf("terraform destroy: %w", err)
|
||||
}
|
||||
|
||||
cmdio.LogString(ctx, "Successfully destroyed resources!")
|
||||
return nil
|
||||
}
|
||||
|
||||
// Destroy returns a [bundle.Mutator] that runs the conceptual equivalent of
|
||||
// `terraform destroy ./plan` from the bundle's ephemeral working directory for Terraform.
|
||||
func Destroy() bundle.Mutator {
|
||||
return &destroy{}
|
||||
}
|
|
@ -44,8 +44,8 @@ func logPlan(ctx context.Context, plan *tfjson.Plan) error {
|
|||
type PlanGoal string
|
||||
|
||||
var (
|
||||
PlanDeploy = PlanGoal("deploy")
|
||||
PlanDestroy = PlanGoal("destroy")
|
||||
PlanGoalDeploy = PlanGoal("deploy")
|
||||
PlanGoalDestroy = PlanGoal("destroy")
|
||||
)
|
||||
|
||||
type plan struct {
|
||||
|
@ -75,7 +75,7 @@ func (p *plan) Apply(ctx context.Context, b *bundle.Bundle) error {
|
|||
return err
|
||||
}
|
||||
planPath := filepath.Join(tfDir, "plan")
|
||||
destroy := p.goal == PlanDestroy
|
||||
destroy := p.goal == PlanGoalDestroy
|
||||
|
||||
notEmpty, err := tf.Plan(ctx, tfexec.Destroy(destroy), tfexec.Out(planPath))
|
||||
if err != nil {
|
||||
|
|
|
@ -19,8 +19,8 @@ func Deploy() bundle.Mutator {
|
|||
terraform.Interpolate(),
|
||||
terraform.Write(),
|
||||
terraform.StatePull(),
|
||||
terraform.Plan(terraform.PlanGoal("deploy")),
|
||||
terraform.Apply(),
|
||||
terraform.Plan(terraform.PlanGoalDeploy),
|
||||
terraform.Apply(terraform.ApplyGoalDeploy),
|
||||
terraform.StatePush(),
|
||||
),
|
||||
lock.Release(lock.GoalDeploy),
|
||||
|
|
|
@ -15,8 +15,8 @@ func Destroy() bundle.Mutator {
|
|||
bundle.Defer(
|
||||
bundle.Seq(
|
||||
terraform.StatePull(),
|
||||
terraform.Plan(terraform.PlanGoal("destroy")),
|
||||
terraform.Destroy(),
|
||||
terraform.Plan(terraform.PlanGoalDestroy),
|
||||
terraform.Apply(terraform.ApplyGoalDestroy),
|
||||
terraform.StatePush(),
|
||||
files.Delete(),
|
||||
),
|
||||
|
|
Loading…
Reference in New Issue