github.com/jaredpalmer/terraform@v1.1.0-alpha20210908.0.20210911170307-88705c943a03/internal/command/refresh.go (about)

     1  package command
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  
     7  	"github.com/hashicorp/terraform/internal/backend"
     8  	"github.com/hashicorp/terraform/internal/command/arguments"
     9  	"github.com/hashicorp/terraform/internal/command/views"
    10  	"github.com/hashicorp/terraform/internal/tfdiags"
    11  )
    12  
    13  // RefreshCommand is a cli.Command implementation that refreshes the state
    14  // file.
    15  type RefreshCommand struct {
    16  	Meta
    17  }
    18  
    19  func (c *RefreshCommand) Run(rawArgs []string) int {
    20  	// Parse and apply global view arguments
    21  	common, rawArgs := arguments.ParseView(rawArgs)
    22  	c.View.Configure(common)
    23  
    24  	// Parse and validate flags
    25  	args, diags := arguments.ParseRefresh(rawArgs)
    26  
    27  	// Instantiate the view, even if there are flag errors, so that we render
    28  	// diagnostics according to the desired view
    29  	view := views.NewRefresh(args.ViewType, c.View)
    30  
    31  	if diags.HasErrors() {
    32  		view.Diagnostics(diags)
    33  		view.HelpPrompt()
    34  		return 1
    35  	}
    36  
    37  	// Check for user-supplied plugin path
    38  	var err error
    39  	if c.pluginPath, err = c.loadPluginPath(); err != nil {
    40  		diags = diags.Append(err)
    41  		view.Diagnostics(diags)
    42  		return 1
    43  	}
    44  
    45  	// FIXME: the -input flag value is needed to initialize the backend and the
    46  	// operation, but there is no clear path to pass this value down, so we
    47  	// continue to mutate the Meta object state for now.
    48  	c.Meta.input = args.InputEnabled
    49  
    50  	// FIXME: the -parallelism flag is used to control the concurrency of
    51  	// Terraform operations. At the moment, this value is used both to
    52  	// initialize the backend via the ContextOpts field inside CLIOpts, and to
    53  	// set a largely unused field on the Operation request. Again, there is no
    54  	// clear path to pass this value down, so we continue to mutate the Meta
    55  	// object state for now.
    56  	c.Meta.parallelism = args.Operation.Parallelism
    57  
    58  	// Prepare the backend with the backend-specific arguments
    59  	be, beDiags := c.PrepareBackend(args.State)
    60  	diags = diags.Append(beDiags)
    61  	if diags.HasErrors() {
    62  		view.Diagnostics(diags)
    63  		return 1
    64  	}
    65  
    66  	// Build the operation request
    67  	opReq, opDiags := c.OperationRequest(be, view, args.Operation)
    68  	diags = diags.Append(opDiags)
    69  	if diags.HasErrors() {
    70  		view.Diagnostics(diags)
    71  		return 1
    72  	}
    73  
    74  	// Collect variable value and add them to the operation request
    75  	diags = diags.Append(c.GatherVariables(opReq, args.Vars))
    76  	if diags.HasErrors() {
    77  		view.Diagnostics(diags)
    78  		return 1
    79  	}
    80  
    81  	// Before we delegate to the backend, we'll print any warning diagnostics
    82  	// we've accumulated here, since the backend will start fresh with its own
    83  	// diagnostics.
    84  	view.Diagnostics(diags)
    85  	diags = nil
    86  
    87  	// Perform the operation
    88  	op, err := c.RunOperation(be, opReq)
    89  	if err != nil {
    90  		diags = diags.Append(err)
    91  		view.Diagnostics(diags)
    92  		return 1
    93  	}
    94  
    95  	if op.State != nil {
    96  		view.Outputs(op.State.RootModule().OutputValues)
    97  	}
    98  
    99  	return op.Result.ExitStatus()
   100  }
   101  
   102  func (c *RefreshCommand) PrepareBackend(args *arguments.State) (backend.Enhanced, tfdiags.Diagnostics) {
   103  	// FIXME: we need to apply the state arguments to the meta object here
   104  	// because they are later used when initializing the backend. Carving a
   105  	// path to pass these arguments to the functions that need them is
   106  	// difficult but would make their use easier to understand.
   107  	c.Meta.applyStateArguments(args)
   108  
   109  	backendConfig, diags := c.loadBackendConfig(".")
   110  	if diags.HasErrors() {
   111  		return nil, diags
   112  	}
   113  
   114  	// Load the backend
   115  	be, beDiags := c.Backend(&BackendOpts{
   116  		Config: backendConfig,
   117  	})
   118  	diags = diags.Append(beDiags)
   119  	if beDiags.HasErrors() {
   120  		return nil, diags
   121  	}
   122  
   123  	return be, diags
   124  }
   125  
   126  func (c *RefreshCommand) OperationRequest(be backend.Enhanced, view views.Refresh, args *arguments.Operation,
   127  ) (*backend.Operation, tfdiags.Diagnostics) {
   128  	var diags tfdiags.Diagnostics
   129  
   130  	// Build the operation
   131  	opReq := c.Operation(be)
   132  	opReq.ConfigDir = "."
   133  	opReq.Hooks = view.Hooks()
   134  	opReq.Targets = args.Targets
   135  	opReq.Type = backend.OperationTypeRefresh
   136  	opReq.View = view.Operation()
   137  
   138  	var err error
   139  	opReq.ConfigLoader, err = c.initConfigLoader()
   140  	if err != nil {
   141  		diags = diags.Append(fmt.Errorf("Failed to initialize config loader: %s", err))
   142  		return nil, diags
   143  	}
   144  
   145  	return opReq, diags
   146  }
   147  
   148  func (c *RefreshCommand) GatherVariables(opReq *backend.Operation, args *arguments.Vars) tfdiags.Diagnostics {
   149  	var diags tfdiags.Diagnostics
   150  
   151  	// FIXME the arguments package currently trivially gathers variable related
   152  	// arguments in a heterogenous slice, in order to minimize the number of
   153  	// code paths gathering variables during the transition to this structure.
   154  	// Once all commands that gather variables have been converted to this
   155  	// structure, we could move the variable gathering code to the arguments
   156  	// package directly, removing this shim layer.
   157  
   158  	varArgs := args.All()
   159  	items := make([]rawFlag, len(varArgs))
   160  	for i := range varArgs {
   161  		items[i].Name = varArgs[i].Name
   162  		items[i].Value = varArgs[i].Value
   163  	}
   164  	c.Meta.variableArgs = rawFlags{items: &items}
   165  	opReq.Variables, diags = c.collectVariableValues()
   166  
   167  	return diags
   168  }
   169  
   170  func (c *RefreshCommand) Help() string {
   171  	helpText := `
   172  Usage: terraform [global options] refresh [options]
   173  
   174    Update the state file of your infrastructure with metadata that matches
   175    the physical resources they are tracking.
   176  
   177    This will not modify your infrastructure, but it can modify your
   178    state file to update metadata. This metadata might cause new changes
   179    to occur when you generate a plan or call apply next.
   180  
   181  Options:
   182  
   183    -compact-warnings   If Terraform produces any warnings that are not
   184                        accompanied by errors, show them in a more compact form
   185                        that includes only the summary messages.
   186  
   187    -input=true         Ask for input for variables if not directly set.
   188  
   189    -lock=false         Don't hold a state lock during the operation. This is
   190                        dangerous if others might concurrently run commands
   191                        against the same workspace.
   192  
   193    -lock-timeout=0s    Duration to retry a state lock.
   194  
   195    -no-color           If specified, output won't contain any color.
   196  
   197    -target=resource    Resource to target. Operation will be limited to this
   198                        resource and its dependencies. This flag can be used
   199                        multiple times.
   200  
   201    -var 'foo=bar'      Set a variable in the Terraform configuration. This
   202                        flag can be set multiple times.
   203  
   204    -var-file=foo       Set variables in the Terraform configuration from
   205                        a file. If "terraform.tfvars" or any ".auto.tfvars"
   206                        files are present, they will be automatically loaded.
   207  
   208    -state, state-out, and -backup are legacy options supported for the local
   209    backend only. For more information, see the local backend's documentation.
   210  `
   211  	return strings.TrimSpace(helpText)
   212  }
   213  
   214  func (c *RefreshCommand) Synopsis() string {
   215  	return "Update the state to match remote systems"
   216  }