github.com/rstandt/terraform@v0.12.32-0.20230710220336-b1063613405c/commands.go (about) 1 package main 2 3 import ( 4 "os" 5 "os/signal" 6 7 "github.com/mitchellh/cli" 8 9 "github.com/hashicorp/go-plugin" 10 svchost "github.com/hashicorp/terraform-svchost" 11 "github.com/hashicorp/terraform-svchost/auth" 12 "github.com/hashicorp/terraform-svchost/disco" 13 "github.com/hashicorp/terraform/addrs" 14 "github.com/hashicorp/terraform/command" 15 "github.com/hashicorp/terraform/command/cliconfig" 16 "github.com/hashicorp/terraform/command/webbrowser" 17 pluginDiscovery "github.com/hashicorp/terraform/plugin/discovery" 18 ) 19 20 // runningInAutomationEnvName gives the name of an environment variable that 21 // can be set to any non-empty value in order to suppress certain messages 22 // that assume that Terraform is being run from a command prompt. 23 const runningInAutomationEnvName = "TF_IN_AUTOMATION" 24 25 // Commands is the mapping of all the available Terraform commands. 26 var Commands map[string]cli.CommandFactory 27 var PlumbingCommands map[string]struct{} 28 29 // Ui is the cli.Ui used for communicating to the outside world. 30 var Ui cli.Ui 31 32 // PluginOverrides is set from wrappedMain during configuration processing 33 // and then eventually passed to the "command" package to specify alternative 34 // plugin locations via the legacy configuration file mechanism. 35 var PluginOverrides command.PluginOverrides 36 37 const ( 38 ErrorPrefix = "e:" 39 OutputPrefix = "o:" 40 ) 41 42 func initCommands(config *cliconfig.Config, services *disco.Disco, unmanagedProviders map[addrs.Provider]*plugin.ReattachConfig) { 43 var inAutomation bool 44 if v := os.Getenv(runningInAutomationEnvName); v != "" { 45 inAutomation = true 46 } 47 48 for userHost, hostConfig := range config.Hosts { 49 host, err := svchost.ForComparison(userHost) 50 if err != nil { 51 // We expect the config was already validated by the time we get 52 // here, so we'll just ignore invalid hostnames. 53 continue 54 } 55 services.ForceHostServices(host, hostConfig.Services) 56 } 57 58 configDir, err := cliconfig.ConfigDir() 59 if err != nil { 60 configDir = "" // No config dir available (e.g. looking up a home directory failed) 61 } 62 63 dataDir := os.Getenv("TF_DATA_DIR") 64 65 meta := command.Meta{ 66 Color: true, 67 GlobalPluginDirs: globalPluginDirs(), 68 PluginOverrides: &PluginOverrides, 69 Ui: Ui, 70 71 Services: services, 72 BrowserLauncher: webbrowser.NewNativeLauncher(), 73 74 RunningInAutomation: inAutomation, 75 CLIConfigDir: configDir, 76 PluginCacheDir: config.PluginCacheDir, 77 OverrideDataDir: dataDir, 78 79 ShutdownCh: makeShutdownCh(), 80 UnmanagedProviders: unmanagedProviders, 81 } 82 83 // The command list is included in the terraform -help 84 // output, which is in turn included in the docs at 85 // website/source/docs/commands/index.html.markdown; if you 86 // add, remove or reclassify commands then consider updating 87 // that to match. 88 89 PlumbingCommands = map[string]struct{}{ 90 "state": struct{}{}, // includes all subcommands 91 "debug": struct{}{}, // includes all subcommands 92 "force-unlock": struct{}{}, 93 "push": struct{}{}, 94 "0.12upgrade": struct{}{}, 95 } 96 97 Commands = map[string]cli.CommandFactory{ 98 "apply": func() (cli.Command, error) { 99 return &command.ApplyCommand{ 100 Meta: meta, 101 }, nil 102 }, 103 104 "console": func() (cli.Command, error) { 105 return &command.ConsoleCommand{ 106 Meta: meta, 107 }, nil 108 }, 109 110 "destroy": func() (cli.Command, error) { 111 return &command.ApplyCommand{ 112 Meta: meta, 113 Destroy: true, 114 }, nil 115 }, 116 117 "env": func() (cli.Command, error) { 118 return &command.WorkspaceCommand{ 119 Meta: meta, 120 LegacyName: true, 121 }, nil 122 }, 123 124 "env list": func() (cli.Command, error) { 125 return &command.WorkspaceListCommand{ 126 Meta: meta, 127 LegacyName: true, 128 }, nil 129 }, 130 131 "env select": func() (cli.Command, error) { 132 return &command.WorkspaceSelectCommand{ 133 Meta: meta, 134 LegacyName: true, 135 }, nil 136 }, 137 138 "env new": func() (cli.Command, error) { 139 return &command.WorkspaceNewCommand{ 140 Meta: meta, 141 LegacyName: true, 142 }, nil 143 }, 144 145 "env delete": func() (cli.Command, error) { 146 return &command.WorkspaceDeleteCommand{ 147 Meta: meta, 148 LegacyName: true, 149 }, nil 150 }, 151 152 "fmt": func() (cli.Command, error) { 153 return &command.FmtCommand{ 154 Meta: meta, 155 }, nil 156 }, 157 158 "get": func() (cli.Command, error) { 159 return &command.GetCommand{ 160 Meta: meta, 161 }, nil 162 }, 163 164 "graph": func() (cli.Command, error) { 165 return &command.GraphCommand{ 166 Meta: meta, 167 }, nil 168 }, 169 170 "import": func() (cli.Command, error) { 171 return &command.ImportCommand{ 172 Meta: meta, 173 }, nil 174 }, 175 176 "init": func() (cli.Command, error) { 177 return &command.InitCommand{ 178 Meta: meta, 179 }, nil 180 }, 181 182 "internal-plugin": func() (cli.Command, error) { 183 return &command.InternalPluginCommand{ 184 Meta: meta, 185 }, nil 186 }, 187 188 "login": func() (cli.Command, error) { 189 return &command.LoginCommand{ 190 Meta: meta, 191 }, nil 192 }, 193 194 "logout": func() (cli.Command, error) { 195 return &command.LogoutCommand{ 196 Meta: meta, 197 }, nil 198 }, 199 200 "output": func() (cli.Command, error) { 201 return &command.OutputCommand{ 202 Meta: meta, 203 }, nil 204 }, 205 206 "plan": func() (cli.Command, error) { 207 return &command.PlanCommand{ 208 Meta: meta, 209 }, nil 210 }, 211 212 "providers": func() (cli.Command, error) { 213 return &command.ProvidersCommand{ 214 Meta: meta, 215 }, nil 216 }, 217 218 "providers schema": func() (cli.Command, error) { 219 return &command.ProvidersSchemaCommand{ 220 Meta: meta, 221 }, nil 222 }, 223 224 "push": func() (cli.Command, error) { 225 return &command.PushCommand{ 226 Meta: meta, 227 }, nil 228 }, 229 230 "refresh": func() (cli.Command, error) { 231 return &command.RefreshCommand{ 232 Meta: meta, 233 }, nil 234 }, 235 236 "show": func() (cli.Command, error) { 237 return &command.ShowCommand{ 238 Meta: meta, 239 }, nil 240 }, 241 242 "taint": func() (cli.Command, error) { 243 return &command.TaintCommand{ 244 Meta: meta, 245 }, nil 246 }, 247 248 "validate": func() (cli.Command, error) { 249 return &command.ValidateCommand{ 250 Meta: meta, 251 }, nil 252 }, 253 254 "version": func() (cli.Command, error) { 255 return &command.VersionCommand{ 256 Meta: meta, 257 Revision: GitCommit, 258 Version: Version, 259 VersionPrerelease: VersionPrerelease, 260 CheckFunc: commandVersionCheck, 261 }, nil 262 }, 263 264 "untaint": func() (cli.Command, error) { 265 return &command.UntaintCommand{ 266 Meta: meta, 267 }, nil 268 }, 269 270 "workspace": func() (cli.Command, error) { 271 return &command.WorkspaceCommand{ 272 Meta: meta, 273 }, nil 274 }, 275 276 "workspace list": func() (cli.Command, error) { 277 return &command.WorkspaceListCommand{ 278 Meta: meta, 279 }, nil 280 }, 281 282 "workspace select": func() (cli.Command, error) { 283 return &command.WorkspaceSelectCommand{ 284 Meta: meta, 285 }, nil 286 }, 287 288 "workspace show": func() (cli.Command, error) { 289 return &command.WorkspaceShowCommand{ 290 Meta: meta, 291 }, nil 292 }, 293 294 "workspace new": func() (cli.Command, error) { 295 return &command.WorkspaceNewCommand{ 296 Meta: meta, 297 }, nil 298 }, 299 300 "workspace delete": func() (cli.Command, error) { 301 return &command.WorkspaceDeleteCommand{ 302 Meta: meta, 303 }, nil 304 }, 305 306 //----------------------------------------------------------- 307 // Plumbing 308 //----------------------------------------------------------- 309 310 "0.12upgrade": func() (cli.Command, error) { 311 return &command.ZeroTwelveUpgradeCommand{ 312 Meta: meta, 313 }, nil 314 }, 315 316 "debug": func() (cli.Command, error) { 317 return &command.DebugCommand{ 318 Meta: meta, 319 }, nil 320 }, 321 322 "debug json2dot": func() (cli.Command, error) { 323 return &command.DebugJSON2DotCommand{ 324 Meta: meta, 325 }, nil 326 }, 327 328 "force-unlock": func() (cli.Command, error) { 329 return &command.UnlockCommand{ 330 Meta: meta, 331 }, nil 332 }, 333 334 "state": func() (cli.Command, error) { 335 return &command.StateCommand{}, nil 336 }, 337 338 "state list": func() (cli.Command, error) { 339 return &command.StateListCommand{ 340 Meta: meta, 341 }, nil 342 }, 343 344 "state rm": func() (cli.Command, error) { 345 return &command.StateRmCommand{ 346 StateMeta: command.StateMeta{ 347 Meta: meta, 348 }, 349 }, nil 350 }, 351 352 "state mv": func() (cli.Command, error) { 353 return &command.StateMvCommand{ 354 StateMeta: command.StateMeta{ 355 Meta: meta, 356 }, 357 }, nil 358 }, 359 360 "state pull": func() (cli.Command, error) { 361 return &command.StatePullCommand{ 362 Meta: meta, 363 }, nil 364 }, 365 366 "state push": func() (cli.Command, error) { 367 return &command.StatePushCommand{ 368 Meta: meta, 369 }, nil 370 }, 371 372 "state show": func() (cli.Command, error) { 373 return &command.StateShowCommand{ 374 Meta: meta, 375 }, nil 376 }, 377 } 378 } 379 380 // makeShutdownCh creates an interrupt listener and returns a channel. 381 // A message will be sent on the channel for every interrupt received. 382 func makeShutdownCh() <-chan struct{} { 383 resultCh := make(chan struct{}) 384 385 signalCh := make(chan os.Signal, 4) 386 signal.Notify(signalCh, ignoreSignals...) 387 signal.Notify(signalCh, forwardSignals...) 388 go func() { 389 for { 390 <-signalCh 391 resultCh <- struct{}{} 392 } 393 }() 394 395 return resultCh 396 } 397 398 func credentialsSource(config *cliconfig.Config) (auth.CredentialsSource, error) { 399 helperPlugins := pluginDiscovery.FindPlugins("credentials", globalPluginDirs()) 400 return config.CredentialsSource(helperPlugins) 401 }