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 }