github.com/iaas-resource-provision/iaas-rpc@v1.0.7-0.20211021023331-ed21f798c408/internal/command/refresh.go (about)

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