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