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