mirror of
https://github.com/hashicorp/terraform.git
synced 2026-02-18 18:29:44 -05:00
use the arguments package for taint commands
This commit is contained in:
parent
492e98ab75
commit
6b83486498
6 changed files with 564 additions and 48 deletions
88
internal/command/arguments/taint.go
Normal file
88
internal/command/arguments/taint.go
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
package arguments
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/terraform/internal/tfdiags"
|
||||
)
|
||||
|
||||
// Taint represents the command-line arguments for the taint command.
|
||||
type Taint struct {
|
||||
// Address is the address of the resource instance to taint.
|
||||
Address string
|
||||
|
||||
// AllowMissing, if true, means the command will succeed even if the
|
||||
// resource is not found in state.
|
||||
AllowMissing bool
|
||||
|
||||
// BackupPath is the path to backup the existing state file before
|
||||
// modifying.
|
||||
BackupPath string
|
||||
|
||||
// StateLock, if true, locks the state file during operations.
|
||||
StateLock bool
|
||||
|
||||
// StateLockTimeout is the duration to retry a state lock.
|
||||
StateLockTimeout time.Duration
|
||||
|
||||
// StatePath is the path to the state file to read and modify.
|
||||
StatePath string
|
||||
|
||||
// StateOutPath is the path to write the updated state file.
|
||||
StateOutPath string
|
||||
|
||||
// IgnoreRemoteVersion, if true, continues even if remote and local
|
||||
// Terraform versions are incompatible.
|
||||
IgnoreRemoteVersion bool
|
||||
}
|
||||
|
||||
// ParseTaint processes CLI arguments, returning a Taint value and errors.
|
||||
// If errors are encountered, a Taint value is still returned representing
|
||||
// the best effort interpretation of the arguments.
|
||||
func ParseTaint(args []string) (*Taint, tfdiags.Diagnostics) {
|
||||
var diags tfdiags.Diagnostics
|
||||
taint := &Taint{
|
||||
StateLock: true,
|
||||
}
|
||||
|
||||
cmdFlags := defaultFlagSet("taint")
|
||||
cmdFlags.BoolVar(&taint.AllowMissing, "allow-missing", false, "allow missing")
|
||||
cmdFlags.StringVar(&taint.BackupPath, "backup", "", "path")
|
||||
cmdFlags.BoolVar(&taint.StateLock, "lock", true, "lock state")
|
||||
cmdFlags.DurationVar(&taint.StateLockTimeout, "lock-timeout", 0, "lock timeout")
|
||||
cmdFlags.StringVar(&taint.StatePath, "state", "", "path")
|
||||
cmdFlags.StringVar(&taint.StateOutPath, "state-out", "", "path")
|
||||
cmdFlags.BoolVar(&taint.IgnoreRemoteVersion, "ignore-remote-version", false, "continue even if remote and local Terraform versions are incompatible")
|
||||
|
||||
if err := cmdFlags.Parse(args); err != nil {
|
||||
diags = diags.Append(tfdiags.Sourceless(
|
||||
tfdiags.Error,
|
||||
"Failed to parse command-line flags",
|
||||
err.Error(),
|
||||
))
|
||||
}
|
||||
|
||||
args = cmdFlags.Args()
|
||||
if len(args) == 0 {
|
||||
diags = diags.Append(tfdiags.Sourceless(
|
||||
tfdiags.Error,
|
||||
"Required argument missing",
|
||||
"The taint command expects exactly one argument: the address of the resource to taint.",
|
||||
))
|
||||
} else if len(args) > 1 {
|
||||
diags = diags.Append(tfdiags.Sourceless(
|
||||
tfdiags.Error,
|
||||
"Too many command line arguments",
|
||||
"The taint command expects exactly one argument: the address of the resource to taint.",
|
||||
))
|
||||
}
|
||||
|
||||
if len(args) > 0 {
|
||||
taint.Address = args[0]
|
||||
}
|
||||
|
||||
return taint, diags
|
||||
}
|
||||
179
internal/command/arguments/taint_test.go
Normal file
179
internal/command/arguments/taint_test.go
Normal file
|
|
@ -0,0 +1,179 @@
|
|||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
package arguments
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/terraform/internal/tfdiags"
|
||||
)
|
||||
|
||||
func TestParseTaint_valid(t *testing.T) {
|
||||
testCases := map[string]struct {
|
||||
args []string
|
||||
want *Taint
|
||||
}{
|
||||
"defaults with address": {
|
||||
[]string{"test_instance.foo"},
|
||||
&Taint{
|
||||
Address: "test_instance.foo",
|
||||
StateLock: true,
|
||||
},
|
||||
},
|
||||
"allow-missing": {
|
||||
[]string{"-allow-missing", "test_instance.foo"},
|
||||
&Taint{
|
||||
Address: "test_instance.foo",
|
||||
AllowMissing: true,
|
||||
StateLock: true,
|
||||
},
|
||||
},
|
||||
"backup": {
|
||||
[]string{"-backup", "backup.tfstate", "test_instance.foo"},
|
||||
&Taint{
|
||||
Address: "test_instance.foo",
|
||||
BackupPath: "backup.tfstate",
|
||||
StateLock: true,
|
||||
},
|
||||
},
|
||||
"lock disabled": {
|
||||
[]string{"-lock=false", "test_instance.foo"},
|
||||
&Taint{
|
||||
Address: "test_instance.foo",
|
||||
StateLock: false,
|
||||
},
|
||||
},
|
||||
"lock-timeout": {
|
||||
[]string{"-lock-timeout=10s", "test_instance.foo"},
|
||||
&Taint{
|
||||
Address: "test_instance.foo",
|
||||
StateLock: true,
|
||||
StateLockTimeout: 10 * time.Second,
|
||||
},
|
||||
},
|
||||
"state": {
|
||||
[]string{"-state=foo.tfstate", "test_instance.foo"},
|
||||
&Taint{
|
||||
Address: "test_instance.foo",
|
||||
StateLock: true,
|
||||
StatePath: "foo.tfstate",
|
||||
},
|
||||
},
|
||||
"state-out": {
|
||||
[]string{"-state-out=foo.tfstate", "test_instance.foo"},
|
||||
&Taint{
|
||||
Address: "test_instance.foo",
|
||||
StateLock: true,
|
||||
StateOutPath: "foo.tfstate",
|
||||
},
|
||||
},
|
||||
"ignore-remote-version": {
|
||||
[]string{"-ignore-remote-version", "test_instance.foo"},
|
||||
&Taint{
|
||||
Address: "test_instance.foo",
|
||||
StateLock: true,
|
||||
IgnoreRemoteVersion: true,
|
||||
},
|
||||
},
|
||||
"all flags": {
|
||||
[]string{
|
||||
"-allow-missing",
|
||||
"-backup=backup.tfstate",
|
||||
"-lock=false",
|
||||
"-lock-timeout=10s",
|
||||
"-state=foo.tfstate",
|
||||
"-state-out=bar.tfstate",
|
||||
"-ignore-remote-version",
|
||||
"module.child.test_instance.foo",
|
||||
},
|
||||
&Taint{
|
||||
Address: "module.child.test_instance.foo",
|
||||
AllowMissing: true,
|
||||
BackupPath: "backup.tfstate",
|
||||
StateLock: false,
|
||||
StateLockTimeout: 10 * time.Second,
|
||||
StatePath: "foo.tfstate",
|
||||
StateOutPath: "bar.tfstate",
|
||||
IgnoreRemoteVersion: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range testCases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
got, diags := ParseTaint(tc.args)
|
||||
if len(diags) > 0 {
|
||||
t.Fatalf("unexpected diags: %v", diags)
|
||||
}
|
||||
if *got != *tc.want {
|
||||
t.Fatalf("unexpected result\n got: %#v\nwant: %#v", got, tc.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseTaint_invalid(t *testing.T) {
|
||||
testCases := map[string]struct {
|
||||
args []string
|
||||
want *Taint
|
||||
wantDiags tfdiags.Diagnostics
|
||||
}{
|
||||
"unknown flag": {
|
||||
[]string{"-unknown"},
|
||||
&Taint{
|
||||
StateLock: true,
|
||||
},
|
||||
tfdiags.Diagnostics{
|
||||
tfdiags.Sourceless(
|
||||
tfdiags.Error,
|
||||
"Failed to parse command-line flags",
|
||||
"flag provided but not defined: -unknown",
|
||||
),
|
||||
tfdiags.Sourceless(
|
||||
tfdiags.Error,
|
||||
"Required argument missing",
|
||||
"The taint command expects exactly one argument: the address of the resource to taint.",
|
||||
),
|
||||
},
|
||||
},
|
||||
"missing address": {
|
||||
nil,
|
||||
&Taint{
|
||||
StateLock: true,
|
||||
},
|
||||
tfdiags.Diagnostics{
|
||||
tfdiags.Sourceless(
|
||||
tfdiags.Error,
|
||||
"Required argument missing",
|
||||
"The taint command expects exactly one argument: the address of the resource to taint.",
|
||||
),
|
||||
},
|
||||
},
|
||||
"too many arguments": {
|
||||
[]string{"test_instance.foo", "test_instance.bar"},
|
||||
&Taint{
|
||||
Address: "test_instance.foo",
|
||||
StateLock: true,
|
||||
},
|
||||
tfdiags.Diagnostics{
|
||||
tfdiags.Sourceless(
|
||||
tfdiags.Error,
|
||||
"Too many command line arguments",
|
||||
"The taint command expects exactly one argument: the address of the resource to taint.",
|
||||
),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range testCases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
got, gotDiags := ParseTaint(tc.args)
|
||||
if *got != *tc.want {
|
||||
t.Fatalf("unexpected result\n got: %#v\nwant: %#v", got, tc.want)
|
||||
}
|
||||
tfdiags.AssertDiagnosticsMatch(t, gotDiags, tc.wantDiags)
|
||||
})
|
||||
}
|
||||
}
|
||||
88
internal/command/arguments/untaint.go
Normal file
88
internal/command/arguments/untaint.go
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
package arguments
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/terraform/internal/tfdiags"
|
||||
)
|
||||
|
||||
// Untaint represents the command-line arguments for the untaint command.
|
||||
type Untaint struct {
|
||||
// Address is the address of the resource instance to untaint.
|
||||
Address string
|
||||
|
||||
// AllowMissing, if true, means the command will succeed even if the
|
||||
// resource is not found in state.
|
||||
AllowMissing bool
|
||||
|
||||
// BackupPath is the path to backup the existing state file before
|
||||
// modifying.
|
||||
BackupPath string
|
||||
|
||||
// StateLock, if true, locks the state file during operations.
|
||||
StateLock bool
|
||||
|
||||
// StateLockTimeout is the duration to retry a state lock.
|
||||
StateLockTimeout time.Duration
|
||||
|
||||
// StatePath is the path to the state file to read and modify.
|
||||
StatePath string
|
||||
|
||||
// StateOutPath is the path to write the updated state file.
|
||||
StateOutPath string
|
||||
|
||||
// IgnoreRemoteVersion, if true, continues even if remote and local
|
||||
// Terraform versions are incompatible.
|
||||
IgnoreRemoteVersion bool
|
||||
}
|
||||
|
||||
// ParseUntaint processes CLI arguments, returning an Untaint value and errors.
|
||||
// If errors are encountered, an Untaint value is still returned representing
|
||||
// the best effort interpretation of the arguments.
|
||||
func ParseUntaint(args []string) (*Untaint, tfdiags.Diagnostics) {
|
||||
var diags tfdiags.Diagnostics
|
||||
untaint := &Untaint{
|
||||
StateLock: true,
|
||||
}
|
||||
|
||||
cmdFlags := defaultFlagSet("untaint")
|
||||
cmdFlags.BoolVar(&untaint.AllowMissing, "allow-missing", false, "allow missing")
|
||||
cmdFlags.StringVar(&untaint.BackupPath, "backup", "", "path")
|
||||
cmdFlags.BoolVar(&untaint.StateLock, "lock", true, "lock state")
|
||||
cmdFlags.DurationVar(&untaint.StateLockTimeout, "lock-timeout", 0, "lock timeout")
|
||||
cmdFlags.StringVar(&untaint.StatePath, "state", "", "path")
|
||||
cmdFlags.StringVar(&untaint.StateOutPath, "state-out", "", "path")
|
||||
cmdFlags.BoolVar(&untaint.IgnoreRemoteVersion, "ignore-remote-version", false, "continue even if remote and local Terraform versions are incompatible")
|
||||
|
||||
if err := cmdFlags.Parse(args); err != nil {
|
||||
diags = diags.Append(tfdiags.Sourceless(
|
||||
tfdiags.Error,
|
||||
"Failed to parse command-line flags",
|
||||
err.Error(),
|
||||
))
|
||||
}
|
||||
|
||||
args = cmdFlags.Args()
|
||||
if len(args) == 0 {
|
||||
diags = diags.Append(tfdiags.Sourceless(
|
||||
tfdiags.Error,
|
||||
"Required argument missing",
|
||||
"The untaint command expects exactly one argument: the address of the resource to untaint.",
|
||||
))
|
||||
} else if len(args) > 1 {
|
||||
diags = diags.Append(tfdiags.Sourceless(
|
||||
tfdiags.Error,
|
||||
"Too many command line arguments",
|
||||
"The untaint command expects exactly one argument: the address of the resource to untaint.",
|
||||
))
|
||||
}
|
||||
|
||||
if len(args) > 0 {
|
||||
untaint.Address = args[0]
|
||||
}
|
||||
|
||||
return untaint, diags
|
||||
}
|
||||
179
internal/command/arguments/untaint_test.go
Normal file
179
internal/command/arguments/untaint_test.go
Normal file
|
|
@ -0,0 +1,179 @@
|
|||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
package arguments
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/terraform/internal/tfdiags"
|
||||
)
|
||||
|
||||
func TestParseUntaint_valid(t *testing.T) {
|
||||
testCases := map[string]struct {
|
||||
args []string
|
||||
want *Untaint
|
||||
}{
|
||||
"defaults with address": {
|
||||
[]string{"test_instance.foo"},
|
||||
&Untaint{
|
||||
Address: "test_instance.foo",
|
||||
StateLock: true,
|
||||
},
|
||||
},
|
||||
"allow-missing": {
|
||||
[]string{"-allow-missing", "test_instance.foo"},
|
||||
&Untaint{
|
||||
Address: "test_instance.foo",
|
||||
AllowMissing: true,
|
||||
StateLock: true,
|
||||
},
|
||||
},
|
||||
"backup": {
|
||||
[]string{"-backup", "backup.tfstate", "test_instance.foo"},
|
||||
&Untaint{
|
||||
Address: "test_instance.foo",
|
||||
BackupPath: "backup.tfstate",
|
||||
StateLock: true,
|
||||
},
|
||||
},
|
||||
"lock disabled": {
|
||||
[]string{"-lock=false", "test_instance.foo"},
|
||||
&Untaint{
|
||||
Address: "test_instance.foo",
|
||||
StateLock: false,
|
||||
},
|
||||
},
|
||||
"lock-timeout": {
|
||||
[]string{"-lock-timeout=10s", "test_instance.foo"},
|
||||
&Untaint{
|
||||
Address: "test_instance.foo",
|
||||
StateLock: true,
|
||||
StateLockTimeout: 10 * time.Second,
|
||||
},
|
||||
},
|
||||
"state": {
|
||||
[]string{"-state=foo.tfstate", "test_instance.foo"},
|
||||
&Untaint{
|
||||
Address: "test_instance.foo",
|
||||
StateLock: true,
|
||||
StatePath: "foo.tfstate",
|
||||
},
|
||||
},
|
||||
"state-out": {
|
||||
[]string{"-state-out=foo.tfstate", "test_instance.foo"},
|
||||
&Untaint{
|
||||
Address: "test_instance.foo",
|
||||
StateLock: true,
|
||||
StateOutPath: "foo.tfstate",
|
||||
},
|
||||
},
|
||||
"ignore-remote-version": {
|
||||
[]string{"-ignore-remote-version", "test_instance.foo"},
|
||||
&Untaint{
|
||||
Address: "test_instance.foo",
|
||||
StateLock: true,
|
||||
IgnoreRemoteVersion: true,
|
||||
},
|
||||
},
|
||||
"all flags": {
|
||||
[]string{
|
||||
"-allow-missing",
|
||||
"-backup=backup.tfstate",
|
||||
"-lock=false",
|
||||
"-lock-timeout=10s",
|
||||
"-state=foo.tfstate",
|
||||
"-state-out=bar.tfstate",
|
||||
"-ignore-remote-version",
|
||||
"module.child.test_instance.foo",
|
||||
},
|
||||
&Untaint{
|
||||
Address: "module.child.test_instance.foo",
|
||||
AllowMissing: true,
|
||||
BackupPath: "backup.tfstate",
|
||||
StateLock: false,
|
||||
StateLockTimeout: 10 * time.Second,
|
||||
StatePath: "foo.tfstate",
|
||||
StateOutPath: "bar.tfstate",
|
||||
IgnoreRemoteVersion: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range testCases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
got, diags := ParseUntaint(tc.args)
|
||||
if len(diags) > 0 {
|
||||
t.Fatalf("unexpected diags: %v", diags)
|
||||
}
|
||||
if *got != *tc.want {
|
||||
t.Fatalf("unexpected result\n got: %#v\nwant: %#v", got, tc.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseUntaint_invalid(t *testing.T) {
|
||||
testCases := map[string]struct {
|
||||
args []string
|
||||
want *Untaint
|
||||
wantDiags tfdiags.Diagnostics
|
||||
}{
|
||||
"unknown flag": {
|
||||
[]string{"-unknown"},
|
||||
&Untaint{
|
||||
StateLock: true,
|
||||
},
|
||||
tfdiags.Diagnostics{
|
||||
tfdiags.Sourceless(
|
||||
tfdiags.Error,
|
||||
"Failed to parse command-line flags",
|
||||
"flag provided but not defined: -unknown",
|
||||
),
|
||||
tfdiags.Sourceless(
|
||||
tfdiags.Error,
|
||||
"Required argument missing",
|
||||
"The untaint command expects exactly one argument: the address of the resource to untaint.",
|
||||
),
|
||||
},
|
||||
},
|
||||
"missing address": {
|
||||
nil,
|
||||
&Untaint{
|
||||
StateLock: true,
|
||||
},
|
||||
tfdiags.Diagnostics{
|
||||
tfdiags.Sourceless(
|
||||
tfdiags.Error,
|
||||
"Required argument missing",
|
||||
"The untaint command expects exactly one argument: the address of the resource to untaint.",
|
||||
),
|
||||
},
|
||||
},
|
||||
"too many arguments": {
|
||||
[]string{"test_instance.foo", "test_instance.bar"},
|
||||
&Untaint{
|
||||
Address: "test_instance.foo",
|
||||
StateLock: true,
|
||||
},
|
||||
tfdiags.Diagnostics{
|
||||
tfdiags.Sourceless(
|
||||
tfdiags.Error,
|
||||
"Too many command line arguments",
|
||||
"The untaint command expects exactly one argument: the address of the resource to untaint.",
|
||||
),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range testCases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
got, gotDiags := ParseUntaint(tc.args)
|
||||
if *got != *tc.want {
|
||||
t.Fatalf("unexpected result\n got: %#v\nwant: %#v", got, tc.want)
|
||||
}
|
||||
tfdiags.AssertDiagnosticsMatch(t, gotDiags, tc.wantDiags)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -22,33 +22,24 @@ type TaintCommand struct {
|
|||
Meta
|
||||
}
|
||||
|
||||
func (c *TaintCommand) Run(args []string) int {
|
||||
args = c.Meta.process(args)
|
||||
var allowMissing bool
|
||||
cmdFlags := c.Meta.ignoreRemoteVersionFlagSet("taint")
|
||||
cmdFlags.BoolVar(&allowMissing, "allow-missing", false, "allow missing")
|
||||
cmdFlags.StringVar(&c.Meta.backupPath, "backup", "", "path")
|
||||
cmdFlags.BoolVar(&c.Meta.stateLock, "lock", true, "lock state")
|
||||
cmdFlags.DurationVar(&c.Meta.stateLockTimeout, "lock-timeout", 0, "lock timeout")
|
||||
cmdFlags.StringVar(&c.Meta.statePath, "state", "", "path")
|
||||
cmdFlags.StringVar(&c.Meta.stateOutPath, "state-out", "", "path")
|
||||
cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
|
||||
if err := cmdFlags.Parse(args); err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("Error parsing command-line flags: %s\n", err.Error()))
|
||||
func (c *TaintCommand) Run(rawArgs []string) int {
|
||||
parsedArgs, parseDiags := arguments.ParseTaint(c.Meta.process(rawArgs))
|
||||
if parseDiags.HasErrors() {
|
||||
c.showDiagnostics(parseDiags)
|
||||
return 1
|
||||
}
|
||||
|
||||
// Copy parsed flags to Meta
|
||||
c.Meta.backupPath = parsedArgs.BackupPath
|
||||
c.Meta.stateLock = parsedArgs.StateLock
|
||||
c.Meta.stateLockTimeout = parsedArgs.StateLockTimeout
|
||||
c.Meta.statePath = parsedArgs.StatePath
|
||||
c.Meta.stateOutPath = parsedArgs.StateOutPath
|
||||
c.Meta.ignoreRemoteVersion = parsedArgs.IgnoreRemoteVersion
|
||||
|
||||
var diags tfdiags.Diagnostics
|
||||
|
||||
// Require the one argument for the resource to taint
|
||||
args = cmdFlags.Args()
|
||||
if len(args) != 1 {
|
||||
c.Ui.Error("The taint command expects exactly one argument.")
|
||||
cmdFlags.Usage()
|
||||
return 1
|
||||
}
|
||||
|
||||
addr, addrDiags := addrs.ParseAbsResourceInstanceStr(args[0])
|
||||
addr, addrDiags := addrs.ParseAbsResourceInstanceStr(parsedArgs.Address)
|
||||
diags = diags.Append(addrDiags)
|
||||
if addrDiags.HasErrors() {
|
||||
c.showDiagnostics(diags)
|
||||
|
|
@ -117,7 +108,7 @@ func (c *TaintCommand) Run(args []string) int {
|
|||
// Get the actual state structure
|
||||
state := stateMgr.State()
|
||||
if state.Empty() {
|
||||
if allowMissing {
|
||||
if parsedArgs.AllowMissing {
|
||||
return c.allowMissingExit(addr)
|
||||
}
|
||||
|
||||
|
|
@ -144,7 +135,7 @@ func (c *TaintCommand) Run(args []string) int {
|
|||
rs := ss.Resource(addr.ContainingResource())
|
||||
is := ss.ResourceInstance(addr)
|
||||
if is == nil {
|
||||
if allowMissing {
|
||||
if parsedArgs.AllowMissing {
|
||||
return c.allowMissingExit(addr)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -22,33 +22,24 @@ type UntaintCommand struct {
|
|||
Meta
|
||||
}
|
||||
|
||||
func (c *UntaintCommand) Run(args []string) int {
|
||||
args = c.Meta.process(args)
|
||||
var allowMissing bool
|
||||
cmdFlags := c.Meta.ignoreRemoteVersionFlagSet("untaint")
|
||||
cmdFlags.BoolVar(&allowMissing, "allow-missing", false, "allow missing")
|
||||
cmdFlags.StringVar(&c.Meta.backupPath, "backup", "", "path")
|
||||
cmdFlags.BoolVar(&c.Meta.stateLock, "lock", true, "lock state")
|
||||
cmdFlags.DurationVar(&c.Meta.stateLockTimeout, "lock-timeout", 0, "lock timeout")
|
||||
cmdFlags.StringVar(&c.Meta.statePath, "state", "", "path")
|
||||
cmdFlags.StringVar(&c.Meta.stateOutPath, "state-out", "", "path")
|
||||
cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
|
||||
if err := cmdFlags.Parse(args); err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("Error parsing command-line flags: %s\n", err.Error()))
|
||||
func (c *UntaintCommand) Run(rawArgs []string) int {
|
||||
parsedArgs, parseDiags := arguments.ParseUntaint(c.Meta.process(rawArgs))
|
||||
if parseDiags.HasErrors() {
|
||||
c.showDiagnostics(parseDiags)
|
||||
return 1
|
||||
}
|
||||
|
||||
// Copy parsed flags to Meta
|
||||
c.Meta.backupPath = parsedArgs.BackupPath
|
||||
c.Meta.stateLock = parsedArgs.StateLock
|
||||
c.Meta.stateLockTimeout = parsedArgs.StateLockTimeout
|
||||
c.Meta.statePath = parsedArgs.StatePath
|
||||
c.Meta.stateOutPath = parsedArgs.StateOutPath
|
||||
c.Meta.ignoreRemoteVersion = parsedArgs.IgnoreRemoteVersion
|
||||
|
||||
var diags tfdiags.Diagnostics
|
||||
|
||||
// Require the one argument for the resource to untaint
|
||||
args = cmdFlags.Args()
|
||||
if len(args) != 1 {
|
||||
c.Ui.Error("The untaint command expects exactly one argument.")
|
||||
cmdFlags.Usage()
|
||||
return 1
|
||||
}
|
||||
|
||||
addr, addrDiags := addrs.ParseAbsResourceInstanceStr(args[0])
|
||||
addr, addrDiags := addrs.ParseAbsResourceInstanceStr(parsedArgs.Address)
|
||||
diags = diags.Append(addrDiags)
|
||||
if addrDiags.HasErrors() {
|
||||
c.showDiagnostics(diags)
|
||||
|
|
@ -107,7 +98,7 @@ func (c *UntaintCommand) Run(args []string) int {
|
|||
// Get the actual state structure
|
||||
state := stateMgr.State()
|
||||
if state.Empty() {
|
||||
if allowMissing {
|
||||
if parsedArgs.AllowMissing {
|
||||
return c.allowMissingExit(addr)
|
||||
}
|
||||
|
||||
|
|
@ -126,7 +117,7 @@ func (c *UntaintCommand) Run(args []string) int {
|
|||
rs := ss.Resource(addr.ContainingResource())
|
||||
is := ss.ResourceInstance(addr)
|
||||
if is == nil {
|
||||
if allowMissing {
|
||||
if parsedArgs.AllowMissing {
|
||||
return c.allowMissingExit(addr)
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue