github.com/graywolf-at-work-2/terraform-vendor@v1.4.5/internal/command/arguments/apply.go (about)

     1  package arguments
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/hashicorp/terraform/internal/plans"
     7  	"github.com/hashicorp/terraform/internal/tfdiags"
     8  )
     9  
    10  // Apply represents the command-line arguments for the apply command.
    11  type Apply struct {
    12  	// State, Operation, and Vars are the common extended flags
    13  	State     *State
    14  	Operation *Operation
    15  	Vars      *Vars
    16  
    17  	// AutoApprove skips the manual verification step for the apply operation.
    18  	AutoApprove bool
    19  
    20  	// InputEnabled is used to disable interactive input for unspecified
    21  	// variable and backend config values. Default is true.
    22  	InputEnabled bool
    23  
    24  	// PlanPath contains an optional path to a stored plan file
    25  	PlanPath string
    26  
    27  	// ViewType specifies which output format to use
    28  	ViewType ViewType
    29  }
    30  
    31  // ParseApply processes CLI arguments, returning an Apply value and errors.
    32  // If errors are encountered, an Apply value is still returned representing
    33  // the best effort interpretation of the arguments.
    34  func ParseApply(args []string) (*Apply, tfdiags.Diagnostics) {
    35  	var diags tfdiags.Diagnostics
    36  	apply := &Apply{
    37  		State:     &State{},
    38  		Operation: &Operation{},
    39  		Vars:      &Vars{},
    40  	}
    41  
    42  	cmdFlags := extendedFlagSet("apply", apply.State, apply.Operation, apply.Vars)
    43  	cmdFlags.BoolVar(&apply.AutoApprove, "auto-approve", false, "auto-approve")
    44  	cmdFlags.BoolVar(&apply.InputEnabled, "input", true, "input")
    45  
    46  	var json bool
    47  	cmdFlags.BoolVar(&json, "json", false, "json")
    48  
    49  	if err := cmdFlags.Parse(args); err != nil {
    50  		diags = diags.Append(tfdiags.Sourceless(
    51  			tfdiags.Error,
    52  			"Failed to parse command-line flags",
    53  			err.Error(),
    54  		))
    55  	}
    56  
    57  	args = cmdFlags.Args()
    58  	if len(args) > 0 {
    59  		apply.PlanPath = args[0]
    60  		args = args[1:]
    61  	}
    62  
    63  	if len(args) > 0 {
    64  		diags = diags.Append(tfdiags.Sourceless(
    65  			tfdiags.Error,
    66  			"Too many command line arguments",
    67  			"Expected at most one positional argument.",
    68  		))
    69  	}
    70  
    71  	// JSON view currently does not support input, so we disable it here.
    72  	if json {
    73  		apply.InputEnabled = false
    74  	}
    75  
    76  	// JSON view cannot confirm apply, so we require either a plan file or
    77  	// auto-approve to be specified. We intentionally fail here rather than
    78  	// override auto-approve, which would be dangerous.
    79  	if json && apply.PlanPath == "" && !apply.AutoApprove {
    80  		diags = diags.Append(tfdiags.Sourceless(
    81  			tfdiags.Error,
    82  			"Plan file or auto-approve required",
    83  			"Terraform cannot ask for interactive approval when -json is set. You can either apply a saved plan file, or enable the -auto-approve option.",
    84  		))
    85  	}
    86  
    87  	diags = diags.Append(apply.Operation.Parse())
    88  
    89  	switch {
    90  	case json:
    91  		apply.ViewType = ViewJSON
    92  	default:
    93  		apply.ViewType = ViewHuman
    94  	}
    95  
    96  	return apply, diags
    97  }
    98  
    99  // ParseApplyDestroy is a special case of ParseApply that deals with the
   100  // "terraform destroy" command, which is effectively an alias for
   101  // "terraform apply -destroy".
   102  func ParseApplyDestroy(args []string) (*Apply, tfdiags.Diagnostics) {
   103  	apply, diags := ParseApply(args)
   104  
   105  	// So far ParseApply was using the command line options like -destroy
   106  	// and -refresh-only to determine the plan mode. For "terraform destroy"
   107  	// we expect neither of those arguments to be set, and so the plan mode
   108  	// should currently be set to NormalMode, which we'll replace with
   109  	// DestroyMode here. If it's already set to something else then that
   110  	// suggests incorrect usage.
   111  	switch apply.Operation.PlanMode {
   112  	case plans.NormalMode:
   113  		// This indicates that the user didn't specify any mode options at
   114  		// all, which is correct, although we know from the command that
   115  		// they actually intended to use DestroyMode here.
   116  		apply.Operation.PlanMode = plans.DestroyMode
   117  	case plans.DestroyMode:
   118  		diags = diags.Append(tfdiags.Sourceless(
   119  			tfdiags.Error,
   120  			"Invalid mode option",
   121  			"The -destroy option is not valid for \"terraform destroy\", because this command always runs in destroy mode.",
   122  		))
   123  	case plans.RefreshOnlyMode:
   124  		diags = diags.Append(tfdiags.Sourceless(
   125  			tfdiags.Error,
   126  			"Invalid mode option",
   127  			"The -refresh-only option is not valid for \"terraform destroy\".",
   128  		))
   129  	default:
   130  		// This is a non-ideal error message for if we forget to handle a
   131  		// newly-handled plan mode in Operation.Parse. Ideally they should all
   132  		// have cases above so we can produce better error messages.
   133  		diags = diags.Append(tfdiags.Sourceless(
   134  			tfdiags.Error,
   135  			"Invalid mode option",
   136  			fmt.Sprintf("The \"terraform destroy\" command doesn't support %s.", apply.Operation.PlanMode),
   137  		))
   138  	}
   139  
   140  	// NOTE: It's also invalid to have apply.PlanPath set in this codepath,
   141  	// but we don't check that in here because we'll return a different error
   142  	// message depending on whether the given path seems to refer to a saved
   143  	// plan file or to a configuration directory. The apply command
   144  	// implementation itself therefore handles this situation.
   145  
   146  	return apply, diags
   147  }