github.com/trawler/terraform@v0.10.8-0.20171106022149-4b1c7a1d9b48/command/providers.go (about)

     1  package command
     2  
     3  import (
     4  	"fmt"
     5  	"sort"
     6  
     7  	"github.com/hashicorp/terraform/moduledeps"
     8  	"github.com/hashicorp/terraform/terraform"
     9  	"github.com/xlab/treeprint"
    10  )
    11  
    12  // ProvidersCommand is a Command implementation that prints out information
    13  // about the providers used in the current configuration/state.
    14  type ProvidersCommand struct {
    15  	Meta
    16  }
    17  
    18  func (c *ProvidersCommand) Help() string {
    19  	return providersCommandHelp
    20  }
    21  
    22  func (c *ProvidersCommand) Synopsis() string {
    23  	return "Prints a tree of the providers used in the configuration"
    24  }
    25  
    26  func (c *ProvidersCommand) Run(args []string) int {
    27  	c.Meta.process(args, false)
    28  
    29  	cmdFlags := c.Meta.flagSet("providers")
    30  	cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
    31  	if err := cmdFlags.Parse(args); err != nil {
    32  		return 1
    33  	}
    34  
    35  	configPath, err := ModulePath(cmdFlags.Args())
    36  	if err != nil {
    37  		c.Ui.Error(err.Error())
    38  		return 1
    39  	}
    40  
    41  	// Load the config
    42  	root, err := c.Module(configPath)
    43  	if err != nil {
    44  		c.Ui.Error(fmt.Sprintf("Failed to load root config module: %s", err))
    45  		return 1
    46  	}
    47  	if root == nil {
    48  		c.Ui.Error(fmt.Sprintf(
    49  			"No configuration files found in the directory: %s\n\n"+
    50  				"This command requires configuration to run.",
    51  			configPath))
    52  		return 1
    53  	}
    54  
    55  	// Validate the config (to ensure the version constraints are valid)
    56  	err = root.Validate()
    57  	if err != nil {
    58  		c.Ui.Error(err.Error())
    59  		return 1
    60  	}
    61  
    62  	// Load the backend
    63  	b, err := c.Backend(&BackendOpts{
    64  		Config: root.Config(),
    65  	})
    66  	if err != nil {
    67  		c.Ui.Error(fmt.Sprintf("Failed to load backend: %s", err))
    68  		return 1
    69  	}
    70  
    71  	// Get the state
    72  	env := c.Workspace()
    73  	state, err := b.State(env)
    74  	if err != nil {
    75  		c.Ui.Error(fmt.Sprintf("Failed to load state: %s", err))
    76  		return 1
    77  	}
    78  	if err := state.RefreshState(); err != nil {
    79  		c.Ui.Error(fmt.Sprintf("Failed to load state: %s", err))
    80  		return 1
    81  	}
    82  
    83  	s := state.State()
    84  
    85  	depTree := terraform.ModuleTreeDependencies(root, s)
    86  	depTree.SortDescendents()
    87  
    88  	printRoot := treeprint.New()
    89  	providersCommandPopulateTreeNode(printRoot, depTree)
    90  
    91  	c.Ui.Output(printRoot.String())
    92  
    93  	return 0
    94  }
    95  
    96  func providersCommandPopulateTreeNode(node treeprint.Tree, deps *moduledeps.Module) {
    97  	names := make([]string, 0, len(deps.Providers))
    98  	for name := range deps.Providers {
    99  		names = append(names, string(name))
   100  	}
   101  	sort.Strings(names)
   102  
   103  	for _, name := range names {
   104  		dep := deps.Providers[moduledeps.ProviderInstance(name)]
   105  		versionsStr := dep.Constraints.String()
   106  		if versionsStr != "" {
   107  			versionsStr = " " + versionsStr
   108  		}
   109  		var reasonStr string
   110  		switch dep.Reason {
   111  		case moduledeps.ProviderDependencyInherited:
   112  			reasonStr = " (inherited)"
   113  		case moduledeps.ProviderDependencyFromState:
   114  			reasonStr = " (from state)"
   115  		}
   116  		node.AddNode(fmt.Sprintf("provider.%s%s%s", name, versionsStr, reasonStr))
   117  	}
   118  
   119  	for _, child := range deps.Children {
   120  		childNode := node.AddBranch(fmt.Sprintf("module.%s", child.Name))
   121  		providersCommandPopulateTreeNode(childNode, child)
   122  	}
   123  }
   124  
   125  const providersCommandHelp = `
   126  Usage: terraform providers [dir]
   127  
   128    Prints out a tree of modules in the referenced configuration annotated with
   129    their provider requirements.
   130  
   131    This provides an overview of all of the provider requirements across all
   132    referenced modules, as an aid to understanding why particular provider
   133    plugins are needed and why particular versions are selected.
   134  
   135  `