github.com/pulumi/terraform@v1.4.0/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/pulumi/terraform/pkg/addrs" 14 "github.com/pulumi/terraform/pkg/command" 15 "github.com/pulumi/terraform/pkg/command/cliconfig" 16 "github.com/pulumi/terraform/pkg/command/views" 17 "github.com/pulumi/terraform/pkg/command/webbrowser" 18 "github.com/pulumi/terraform/pkg/getproviders" 19 pluginDiscovery "github.com/pulumi/terraform/pkg/plugin/discovery" 20 "github.com/pulumi/terraform/pkg/terminal" 21 ) 22 23 // runningInAutomationEnvName gives the name of an environment variable that 24 // can be set to any non-empty value in order to suppress certain messages 25 // that assume that Terraform is being run from a command prompt. 26 const runningInAutomationEnvName = "TF_IN_AUTOMATION" 27 28 // Commands is the mapping of all the available Terraform commands. 29 var Commands map[string]cli.CommandFactory 30 31 // PrimaryCommands is an ordered sequence of the top-level commands (not 32 // subcommands) that we emphasize at the top of our help output. This is 33 // ordered so that we can show them in the typical workflow order, rather 34 // than in alphabetical order. Anything not in this sequence or in the 35 // HiddenCommands set appears under "all other commands". 36 var PrimaryCommands []string 37 38 // HiddenCommands is a set of top-level commands (not subcommands) that are 39 // not advertised in the top-level help at all. This is typically because 40 // they are either just stubs that return an error message about something 41 // no longer being supported or backward-compatibility aliases for other 42 // commands. 43 // 44 // No commands in the PrimaryCommands sequence should also appear in the 45 // HiddenCommands set, because that would be rather silly. 46 var HiddenCommands map[string]struct{} 47 48 // Ui is the cli.Ui used for communicating to the outside world. 49 var Ui cli.Ui 50 51 func initCommands( 52 originalWorkingDir string, 53 streams *terminal.Streams, 54 config *cliconfig.Config, 55 services *disco.Disco, 56 providerSrc getproviders.Source, 57 providerDevOverrides map[addrs.Provider]getproviders.PackageLocalDir, 58 unmanagedProviders map[addrs.Provider]*plugin.ReattachConfig, 59 ) { 60 var inAutomation bool 61 if v := os.Getenv(runningInAutomationEnvName); v != "" { 62 inAutomation = true 63 } 64 65 for userHost, hostConfig := range config.Hosts { 66 host, err := svchost.ForComparison(userHost) 67 if err != nil { 68 // We expect the config was already validated by the time we get 69 // here, so we'll just ignore invalid hostnames. 70 continue 71 } 72 services.ForceHostServices(host, hostConfig.Services) 73 } 74 75 configDir, err := cliconfig.ConfigDir() 76 if err != nil { 77 configDir = "" // No config dir available (e.g. looking up a home directory failed) 78 } 79 80 wd := WorkingDir(originalWorkingDir, os.Getenv("TF_DATA_DIR")) 81 82 meta := command.Meta{ 83 WorkingDir: wd, 84 Streams: streams, 85 View: views.NewView(streams).SetRunningInAutomation(inAutomation), 86 87 Color: true, 88 GlobalPluginDirs: globalPluginDirs(), 89 Ui: Ui, 90 91 Services: services, 92 BrowserLauncher: webbrowser.NewNativeLauncher(), 93 94 RunningInAutomation: inAutomation, 95 CLIConfigDir: configDir, 96 PluginCacheDir: config.PluginCacheDir, 97 98 PluginCacheMayBreakDependencyLockFile: config.PluginCacheMayBreakDependencyLockFile, 99 100 ShutdownCh: makeShutdownCh(), 101 102 ProviderSource: providerSrc, 103 ProviderDevOverrides: providerDevOverrides, 104 UnmanagedProviders: unmanagedProviders, 105 106 AllowExperimentalFeatures: ExperimentsAllowed(), 107 } 108 109 // The command list is included in the terraform -help 110 // output, which is in turn included in the docs at 111 // website/docs/cli/commands/index.html.markdown; if you 112 // add, remove or reclassify commands then consider updating 113 // that to match. 114 115 Commands = map[string]cli.CommandFactory{ 116 "apply": func() (cli.Command, error) { 117 return &command.ApplyCommand{ 118 Meta: meta, 119 }, nil 120 }, 121 122 "console": func() (cli.Command, error) { 123 return &command.ConsoleCommand{ 124 Meta: meta, 125 }, nil 126 }, 127 128 "destroy": func() (cli.Command, error) { 129 return &command.ApplyCommand{ 130 Meta: meta, 131 Destroy: true, 132 }, nil 133 }, 134 135 "env": func() (cli.Command, error) { 136 return &command.WorkspaceCommand{ 137 Meta: meta, 138 LegacyName: true, 139 }, nil 140 }, 141 142 "env list": func() (cli.Command, error) { 143 return &command.WorkspaceListCommand{ 144 Meta: meta, 145 LegacyName: true, 146 }, nil 147 }, 148 149 "env select": func() (cli.Command, error) { 150 return &command.WorkspaceSelectCommand{ 151 Meta: meta, 152 LegacyName: true, 153 }, nil 154 }, 155 156 "env new": func() (cli.Command, error) { 157 return &command.WorkspaceNewCommand{ 158 Meta: meta, 159 LegacyName: true, 160 }, nil 161 }, 162 163 "env delete": func() (cli.Command, error) { 164 return &command.WorkspaceDeleteCommand{ 165 Meta: meta, 166 LegacyName: true, 167 }, nil 168 }, 169 170 "fmt": func() (cli.Command, error) { 171 return &command.FmtCommand{ 172 Meta: meta, 173 }, nil 174 }, 175 176 "get": func() (cli.Command, error) { 177 return &command.GetCommand{ 178 Meta: meta, 179 }, nil 180 }, 181 182 "graph": func() (cli.Command, error) { 183 return &command.GraphCommand{ 184 Meta: meta, 185 }, nil 186 }, 187 188 "import": func() (cli.Command, error) { 189 return &command.ImportCommand{ 190 Meta: meta, 191 }, nil 192 }, 193 194 "init": func() (cli.Command, error) { 195 return &command.InitCommand{ 196 Meta: meta, 197 }, nil 198 }, 199 200 "login": func() (cli.Command, error) { 201 return &command.LoginCommand{ 202 Meta: meta, 203 }, nil 204 }, 205 206 "logout": func() (cli.Command, error) { 207 return &command.LogoutCommand{ 208 Meta: meta, 209 }, nil 210 }, 211 212 "metadata": func() (cli.Command, error) { 213 return &command.MetadataCommand{ 214 Meta: meta, 215 }, nil 216 }, 217 218 "metadata functions": func() (cli.Command, error) { 219 return &command.MetadataFunctionsCommand{ 220 Meta: meta, 221 }, nil 222 }, 223 224 "output": func() (cli.Command, error) { 225 return &command.OutputCommand{ 226 Meta: meta, 227 }, nil 228 }, 229 230 "plan": func() (cli.Command, error) { 231 return &command.PlanCommand{ 232 Meta: meta, 233 }, nil 234 }, 235 236 "providers": func() (cli.Command, error) { 237 return &command.ProvidersCommand{ 238 Meta: meta, 239 }, nil 240 }, 241 242 "providers lock": func() (cli.Command, error) { 243 return &command.ProvidersLockCommand{ 244 Meta: meta, 245 }, nil 246 }, 247 248 "providers mirror": func() (cli.Command, error) { 249 return &command.ProvidersMirrorCommand{ 250 Meta: meta, 251 }, nil 252 }, 253 254 "providers schema": func() (cli.Command, error) { 255 return &command.ProvidersSchemaCommand{ 256 Meta: meta, 257 }, nil 258 }, 259 260 "push": func() (cli.Command, error) { 261 return &command.PushCommand{ 262 Meta: meta, 263 }, nil 264 }, 265 266 "refresh": func() (cli.Command, error) { 267 return &command.RefreshCommand{ 268 Meta: meta, 269 }, nil 270 }, 271 272 "show": func() (cli.Command, error) { 273 return &command.ShowCommand{ 274 Meta: meta, 275 }, nil 276 }, 277 278 "taint": func() (cli.Command, error) { 279 return &command.TaintCommand{ 280 Meta: meta, 281 }, nil 282 }, 283 284 "test": func() (cli.Command, error) { 285 return &command.TestCommand{ 286 Meta: meta, 287 }, nil 288 }, 289 290 "validate": func() (cli.Command, error) { 291 return &command.ValidateCommand{ 292 Meta: meta, 293 }, nil 294 }, 295 296 "version": func() (cli.Command, error) { 297 return &command.VersionCommand{ 298 Meta: meta, 299 Version: Version, 300 VersionPrerelease: VersionPrerelease, 301 Platform: getproviders.CurrentPlatform, 302 CheckFunc: commandVersionCheck, 303 }, nil 304 }, 305 306 "untaint": func() (cli.Command, error) { 307 return &command.UntaintCommand{ 308 Meta: meta, 309 }, nil 310 }, 311 312 "workspace": func() (cli.Command, error) { 313 return &command.WorkspaceCommand{ 314 Meta: meta, 315 }, nil 316 }, 317 318 "workspace list": func() (cli.Command, error) { 319 return &command.WorkspaceListCommand{ 320 Meta: meta, 321 }, nil 322 }, 323 324 "workspace select": func() (cli.Command, error) { 325 return &command.WorkspaceSelectCommand{ 326 Meta: meta, 327 }, nil 328 }, 329 330 "workspace show": func() (cli.Command, error) { 331 return &command.WorkspaceShowCommand{ 332 Meta: meta, 333 }, nil 334 }, 335 336 "workspace new": func() (cli.Command, error) { 337 return &command.WorkspaceNewCommand{ 338 Meta: meta, 339 }, nil 340 }, 341 342 "workspace delete": func() (cli.Command, error) { 343 return &command.WorkspaceDeleteCommand{ 344 Meta: meta, 345 }, nil 346 }, 347 348 //----------------------------------------------------------- 349 // Plumbing 350 //----------------------------------------------------------- 351 352 "force-unlock": func() (cli.Command, error) { 353 return &command.UnlockCommand{ 354 Meta: meta, 355 }, nil 356 }, 357 358 "state": func() (cli.Command, error) { 359 return &command.StateCommand{}, nil 360 }, 361 362 "state list": func() (cli.Command, error) { 363 return &command.StateListCommand{ 364 Meta: meta, 365 }, nil 366 }, 367 368 "state rm": func() (cli.Command, error) { 369 return &command.StateRmCommand{ 370 StateMeta: command.StateMeta{ 371 Meta: meta, 372 }, 373 }, nil 374 }, 375 376 "state mv": func() (cli.Command, error) { 377 return &command.StateMvCommand{ 378 StateMeta: command.StateMeta{ 379 Meta: meta, 380 }, 381 }, nil 382 }, 383 384 "state pull": func() (cli.Command, error) { 385 return &command.StatePullCommand{ 386 Meta: meta, 387 }, nil 388 }, 389 390 "state push": func() (cli.Command, error) { 391 return &command.StatePushCommand{ 392 Meta: meta, 393 }, nil 394 }, 395 396 "state show": func() (cli.Command, error) { 397 return &command.StateShowCommand{ 398 Meta: meta, 399 }, nil 400 }, 401 402 "state replace-provider": func() (cli.Command, error) { 403 return &command.StateReplaceProviderCommand{ 404 StateMeta: command.StateMeta{ 405 Meta: meta, 406 }, 407 }, nil 408 }, 409 } 410 411 PrimaryCommands = []string{ 412 "init", 413 "validate", 414 "plan", 415 "apply", 416 "destroy", 417 } 418 419 HiddenCommands = map[string]struct{}{ 420 "env": struct{}{}, 421 "internal-plugin": struct{}{}, 422 "push": struct{}{}, 423 } 424 425 } 426 427 // makeShutdownCh creates an interrupt listener and returns a channel. 428 // A message will be sent on the channel for every interrupt received. 429 func makeShutdownCh() <-chan struct{} { 430 resultCh := make(chan struct{}) 431 432 signalCh := make(chan os.Signal, 4) 433 signal.Notify(signalCh, ignoreSignals...) 434 signal.Notify(signalCh, forwardSignals...) 435 go func() { 436 for { 437 <-signalCh 438 resultCh <- struct{}{} 439 } 440 }() 441 442 return resultCh 443 } 444 445 func credentialsSource(config *cliconfig.Config) (auth.CredentialsSource, error) { 446 helperPlugins := pluginDiscovery.FindPlugins("credentials", globalPluginDirs()) 447 return config.CredentialsSource(helperPlugins) 448 }