github.com/rstandt/terraform@v0.12.32-0.20230710220336-b1063613405c/command/state_rm.go (about)

     1  package command
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"strings"
     7  
     8  	"github.com/hashicorp/terraform/addrs"
     9  	"github.com/hashicorp/terraform/command/clistate"
    10  	"github.com/hashicorp/terraform/tfdiags"
    11  	"github.com/mitchellh/cli"
    12  )
    13  
    14  // StateRmCommand is a Command implementation that shows a single resource.
    15  type StateRmCommand struct {
    16  	StateMeta
    17  }
    18  
    19  func (c *StateRmCommand) Run(args []string) int {
    20  	args, err := c.Meta.process(args, true)
    21  	if err != nil {
    22  		return 1
    23  	}
    24  
    25  	var dryRun bool
    26  	cmdFlags := c.Meta.defaultFlagSet("state rm")
    27  	cmdFlags.BoolVar(&dryRun, "dry-run", false, "dry run")
    28  	cmdFlags.StringVar(&c.backupPath, "backup", "-", "backup")
    29  	cmdFlags.BoolVar(&c.Meta.stateLock, "lock", true, "lock state")
    30  	cmdFlags.DurationVar(&c.Meta.stateLockTimeout, "lock-timeout", 0, "lock timeout")
    31  	cmdFlags.StringVar(&c.statePath, "state", "", "path")
    32  	if err := cmdFlags.Parse(args); err != nil {
    33  		c.Ui.Error(fmt.Sprintf("Error parsing command-line flags: %s\n", err.Error()))
    34  		return 1
    35  	}
    36  
    37  	args = cmdFlags.Args()
    38  	if len(args) < 1 {
    39  		c.Ui.Error("At least one address is required.\n")
    40  		return cli.RunResultHelp
    41  	}
    42  
    43  	// Get the state
    44  	stateMgr, err := c.State()
    45  	if err != nil {
    46  		c.Ui.Error(fmt.Sprintf(errStateLoadingState, err))
    47  		return 1
    48  	}
    49  
    50  	if c.stateLock {
    51  		stateLocker := clistate.NewLocker(context.Background(), c.stateLockTimeout, c.Ui, c.Colorize())
    52  		if err := stateLocker.Lock(stateMgr, "state-rm"); err != nil {
    53  			c.Ui.Error(fmt.Sprintf("Error locking state: %s", err))
    54  			return 1
    55  		}
    56  		defer stateLocker.Unlock(nil)
    57  	}
    58  
    59  	if err := stateMgr.RefreshState(); err != nil {
    60  		c.Ui.Error(fmt.Sprintf("Failed to refresh state: %s", err))
    61  		return 1
    62  	}
    63  
    64  	state := stateMgr.State()
    65  	if state == nil {
    66  		c.Ui.Error(fmt.Sprintf(errStateNotFound))
    67  		return 1
    68  	}
    69  
    70  	// This command primarily works with resource instances, though it will
    71  	// also clean up any modules and resources left empty by actions it takes.
    72  	var addrs []addrs.AbsResourceInstance
    73  	var diags tfdiags.Diagnostics
    74  	for _, addrStr := range args {
    75  		moreAddrs, moreDiags := c.lookupResourceInstanceAddr(state, true, addrStr)
    76  		addrs = append(addrs, moreAddrs...)
    77  		diags = diags.Append(moreDiags)
    78  	}
    79  	if diags.HasErrors() {
    80  		c.showDiagnostics(diags)
    81  		return 1
    82  	}
    83  
    84  	prefix := "Removed "
    85  	if dryRun {
    86  		prefix = "Would remove "
    87  	}
    88  
    89  	var isCount int
    90  	ss := state.SyncWrapper()
    91  	for _, addr := range addrs {
    92  		isCount++
    93  		c.Ui.Output(prefix + addr.String())
    94  		if !dryRun {
    95  			ss.ForgetResourceInstanceAll(addr)
    96  			ss.RemoveResourceIfEmpty(addr.ContainingResource())
    97  		}
    98  	}
    99  
   100  	if dryRun {
   101  		if isCount == 0 {
   102  			c.Ui.Output("Would have removed nothing.")
   103  		}
   104  		return 0 // This is as far as we go in dry-run mode
   105  	}
   106  
   107  	if err := stateMgr.WriteState(state); err != nil {
   108  		c.Ui.Error(fmt.Sprintf(errStateRmPersist, err))
   109  		return 1
   110  	}
   111  	if err := stateMgr.PersistState(); err != nil {
   112  		c.Ui.Error(fmt.Sprintf(errStateRmPersist, err))
   113  		return 1
   114  	}
   115  
   116  	if len(diags) > 0 {
   117  		c.showDiagnostics(diags)
   118  	}
   119  
   120  	if isCount == 0 {
   121  		c.Ui.Output("No matching resource instances found.")
   122  	} else {
   123  		c.Ui.Output(fmt.Sprintf("Successfully removed %d resource instance(s).", isCount))
   124  	}
   125  	return 0
   126  }
   127  
   128  func (c *StateRmCommand) Help() string {
   129  	helpText := `
   130  Usage: terraform state rm [options] ADDRESS...
   131  
   132    Remove one or more items from the Terraform state, causing Terraform to
   133    "forget" those items without first destroying them in the remote system.
   134  
   135    This command removes one or more resource instances from the Terraform state
   136    based on the addresses given. You can view and list the available instances
   137    with "terraform state list".
   138  
   139    If you give the address of an entire module then all of the instances in
   140    that module and any of its child modules will be removed from the state.
   141  
   142    If you give the address of a resource that has "count" or "for_each" set,
   143    all of the instances of that resource will be removed from the state.
   144  
   145  Options:
   146  
   147    -dry-run            If set, prints out what would've been removed but
   148                        doesn't actually remove anything.
   149  
   150    -backup=PATH        Path where Terraform should write the backup
   151                        state.
   152  
   153    -lock=true          Lock the state file when locking is supported.
   154  
   155    -lock-timeout=0s    Duration to retry a state lock.
   156  
   157    -state=PATH         Path to the state file to update. Defaults to the current
   158                        workspace state.
   159  
   160  `
   161  	return strings.TrimSpace(helpText)
   162  }
   163  
   164  func (c *StateRmCommand) Synopsis() string {
   165  	return "Remove instances from the state"
   166  }
   167  
   168  const errStateRm = `Error removing items from the state: %s
   169  
   170  The state was not saved. No items were removed from the persisted
   171  state. No backup was created since no modification occurred. Please
   172  resolve the issue above and try again.`
   173  
   174  const errStateRmPersist = `Error saving the state: %s
   175  
   176  The state was not saved. No items were removed from the persisted
   177  state. No backup was created since no modification occurred. Please
   178  resolve the issue above and try again.`