github.com/spirius/terraform@v0.10.0-beta2.0.20170714185654-87b2c0cf8fea/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 `