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 }