github.com/hugorut/terraform@v1.1.3/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/hugorut/terraform/src/addrs" 14 "github.com/hugorut/terraform/src/command" 15 "github.com/hugorut/terraform/src/command/cliconfig" 16 "github.com/hugorut/terraform/src/command/views" 17 "github.com/hugorut/terraform/src/command/webbrowser" 18 "github.com/hugorut/terraform/src/getproviders" 19 pluginDiscovery "github.com/hugorut/terraform/src/plugin/discovery" 20 "github.com/hugorut/terraform/src/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 ShutdownCh: makeShutdownCh(), 99 100 ProviderSource: providerSrc, 101 ProviderDevOverrides: providerDevOverrides, 102 UnmanagedProviders: unmanagedProviders, 103 } 104 105 // The command list is included in the terraform -help 106 // output, which is in turn included in the docs at 107 // website/docs/cli/commands/index.html.markdown; if you 108 // add, remove or reclassify commands then consider updating 109 // that to match. 110 111 Commands = map[string]cli.CommandFactory{ 112 "apply": func() (cli.Command, error) { 113 return &command.ApplyCommand{ 114 Meta: meta, 115 }, nil 116 }, 117 118 "console": func() (cli.Command, error) { 119 return &command.ConsoleCommand{ 120 Meta: meta, 121 }, nil 122 }, 123 124 "destroy": func() (cli.Command, error) { 125 return &command.ApplyCommand{ 126 Meta: meta, 127 Destroy: true, 128 }, nil 129 }, 130 131 "env": func() (cli.Command, error) { 132 return &command.WorkspaceCommand{ 133 Meta: meta, 134 LegacyName: true, 135 }, nil 136 }, 137 138 "env list": func() (cli.Command, error) { 139 return &command.WorkspaceListCommand{ 140 Meta: meta, 141 LegacyName: true, 142 }, nil 143 }, 144 145 "env select": func() (cli.Command, error) { 146 return &command.WorkspaceSelectCommand{ 147 Meta: meta, 148 LegacyName: true, 149 }, nil 150 }, 151 152 "env new": func() (cli.Command, error) { 153 return &command.WorkspaceNewCommand{ 154 Meta: meta, 155 LegacyName: true, 156 }, nil 157 }, 158 159 "env delete": func() (cli.Command, error) { 160 return &command.WorkspaceDeleteCommand{ 161 Meta: meta, 162 LegacyName: true, 163 }, nil 164 }, 165 166 "fmt": func() (cli.Command, error) { 167 return &command.FmtCommand{ 168 Meta: meta, 169 }, nil 170 }, 171 172 "get": func() (cli.Command, error) { 173 return &command.GetCommand{ 174 Meta: meta, 175 }, nil 176 }, 177 178 "graph": func() (cli.Command, error) { 179 return &command.GraphCommand{ 180 Meta: meta, 181 }, nil 182 }, 183 184 "import": func() (cli.Command, error) { 185 return &command.ImportCommand{ 186 Meta: meta, 187 }, nil 188 }, 189 190 "init": func() (cli.Command, error) { 191 return &command.InitCommand{ 192 Meta: meta, 193 }, nil 194 }, 195 196 "login": func() (cli.Command, error) { 197 return &command.LoginCommand{ 198 Meta: meta, 199 }, nil 200 }, 201 202 "logout": func() (cli.Command, error) { 203 return &command.LogoutCommand{ 204 Meta: meta, 205 }, nil 206 }, 207 208 "output": func() (cli.Command, error) { 209 return &command.OutputCommand{ 210 Meta: meta, 211 }, nil 212 }, 213 214 "plan": func() (cli.Command, error) { 215 return &command.PlanCommand{ 216 Meta: meta, 217 }, nil 218 }, 219 220 "providers": func() (cli.Command, error) { 221 return &command.ProvidersCommand{ 222 Meta: meta, 223 }, nil 224 }, 225 226 "providers lock": func() (cli.Command, error) { 227 return &command.ProvidersLockCommand{ 228 Meta: meta, 229 }, nil 230 }, 231 232 "providers mirror": func() (cli.Command, error) { 233 return &command.ProvidersMirrorCommand{ 234 Meta: meta, 235 }, nil 236 }, 237 238 "providers schema": func() (cli.Command, error) { 239 return &command.ProvidersSchemaCommand{ 240 Meta: meta, 241 }, nil 242 }, 243 244 "push": func() (cli.Command, error) { 245 return &command.PushCommand{ 246 Meta: meta, 247 }, nil 248 }, 249 250 "refresh": func() (cli.Command, error) { 251 return &command.RefreshCommand{ 252 Meta: meta, 253 }, nil 254 }, 255 256 "show": func() (cli.Command, error) { 257 return &command.ShowCommand{ 258 Meta: meta, 259 }, nil 260 }, 261 262 "taint": func() (cli.Command, error) { 263 return &command.TaintCommand{ 264 Meta: meta, 265 }, nil 266 }, 267 268 "test": func() (cli.Command, error) { 269 return &command.TestCommand{ 270 Meta: meta, 271 }, nil 272 }, 273 274 "validate": func() (cli.Command, error) { 275 return &command.ValidateCommand{ 276 Meta: meta, 277 }, nil 278 }, 279 280 "version": func() (cli.Command, error) { 281 return &command.VersionCommand{ 282 Meta: meta, 283 Version: Version, 284 VersionPrerelease: VersionPrerelease, 285 Platform: getproviders.CurrentPlatform, 286 CheckFunc: commandVersionCheck, 287 }, nil 288 }, 289 290 "untaint": func() (cli.Command, error) { 291 return &command.UntaintCommand{ 292 Meta: meta, 293 }, nil 294 }, 295 296 "workspace": func() (cli.Command, error) { 297 return &command.WorkspaceCommand{ 298 Meta: meta, 299 }, nil 300 }, 301 302 "workspace list": func() (cli.Command, error) { 303 return &command.WorkspaceListCommand{ 304 Meta: meta, 305 }, nil 306 }, 307 308 "workspace select": func() (cli.Command, error) { 309 return &command.WorkspaceSelectCommand{ 310 Meta: meta, 311 }, nil 312 }, 313 314 "workspace show": func() (cli.Command, error) { 315 return &command.WorkspaceShowCommand{ 316 Meta: meta, 317 }, nil 318 }, 319 320 "workspace new": func() (cli.Command, error) { 321 return &command.WorkspaceNewCommand{ 322 Meta: meta, 323 }, nil 324 }, 325 326 "workspace delete": func() (cli.Command, error) { 327 return &command.WorkspaceDeleteCommand{ 328 Meta: meta, 329 }, nil 330 }, 331 332 //----------------------------------------------------------- 333 // Plumbing 334 //----------------------------------------------------------- 335 336 "force-unlock": func() (cli.Command, error) { 337 return &command.UnlockCommand{ 338 Meta: meta, 339 }, nil 340 }, 341 342 "state": func() (cli.Command, error) { 343 return &command.StateCommand{}, nil 344 }, 345 346 "state list": func() (cli.Command, error) { 347 return &command.StateListCommand{ 348 Meta: meta, 349 }, nil 350 }, 351 352 "state rm": func() (cli.Command, error) { 353 return &command.StateRmCommand{ 354 StateMeta: command.StateMeta{ 355 Meta: meta, 356 }, 357 }, nil 358 }, 359 360 "state mv": func() (cli.Command, error) { 361 return &command.StateMvCommand{ 362 StateMeta: command.StateMeta{ 363 Meta: meta, 364 }, 365 }, nil 366 }, 367 368 "state pull": func() (cli.Command, error) { 369 return &command.StatePullCommand{ 370 Meta: meta, 371 }, nil 372 }, 373 374 "state push": func() (cli.Command, error) { 375 return &command.StatePushCommand{ 376 Meta: meta, 377 }, nil 378 }, 379 380 "state show": func() (cli.Command, error) { 381 return &command.StateShowCommand{ 382 Meta: meta, 383 }, nil 384 }, 385 386 "state replace-provider": func() (cli.Command, error) { 387 return &command.StateReplaceProviderCommand{ 388 StateMeta: command.StateMeta{ 389 Meta: meta, 390 }, 391 }, nil 392 }, 393 } 394 395 PrimaryCommands = []string{ 396 "init", 397 "validate", 398 "plan", 399 "apply", 400 "destroy", 401 } 402 403 HiddenCommands = map[string]struct{}{ 404 "env": struct{}{}, 405 "src-plugin": struct{}{}, 406 "push": struct{}{}, 407 } 408 409 } 410 411 // makeShutdownCh creates an interrupt listener and returns a channel. 412 // A message will be sent on the channel for every interrupt received. 413 func makeShutdownCh() <-chan struct{} { 414 resultCh := make(chan struct{}) 415 416 signalCh := make(chan os.Signal, 4) 417 signal.Notify(signalCh, ignoreSignals...) 418 signal.Notify(signalCh, forwardSignals...) 419 go func() { 420 for { 421 <-signalCh 422 resultCh <- struct{}{} 423 } 424 }() 425 426 return resultCh 427 } 428 429 func credentialsSource(config *cliconfig.Config) (auth.CredentialsSource, error) { 430 helperPlugins := pluginDiscovery.FindPlugins("credentials", globalPluginDirs()) 431 return config.CredentialsSource(helperPlugins) 432 }