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  }