github.com/paultyng/terraform@v0.6.11-0.20180227224804-66ff8f8bed40/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, diags := c.Module(configPath) 43 if diags.HasErrors() { 44 c.showDiagnostics(diags) 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 // Load the backend 56 b, err := c.Backend(&BackendOpts{ 57 Config: root.Config(), 58 }) 59 if err != nil { 60 c.Ui.Error(fmt.Sprintf("Failed to load backend: %s", err)) 61 return 1 62 } 63 64 // Get the state 65 env := c.Workspace() 66 state, err := b.State(env) 67 if err != nil { 68 c.Ui.Error(fmt.Sprintf("Failed to load state: %s", err)) 69 return 1 70 } 71 if err := state.RefreshState(); err != nil { 72 c.Ui.Error(fmt.Sprintf("Failed to load state: %s", err)) 73 return 1 74 } 75 76 s := state.State() 77 78 depTree := terraform.ModuleTreeDependencies(root, s) 79 depTree.SortDescendents() 80 81 printRoot := treeprint.New() 82 providersCommandPopulateTreeNode(printRoot, depTree) 83 84 c.Ui.Output(printRoot.String()) 85 86 c.showDiagnostics(diags) 87 if diags.HasErrors() { 88 return 1 89 } 90 91 return 0 92 } 93 94 func providersCommandPopulateTreeNode(node treeprint.Tree, deps *moduledeps.Module) { 95 names := make([]string, 0, len(deps.Providers)) 96 for name := range deps.Providers { 97 names = append(names, string(name)) 98 } 99 sort.Strings(names) 100 101 for _, name := range names { 102 dep := deps.Providers[moduledeps.ProviderInstance(name)] 103 versionsStr := dep.Constraints.String() 104 if versionsStr != "" { 105 versionsStr = " " + versionsStr 106 } 107 var reasonStr string 108 switch dep.Reason { 109 case moduledeps.ProviderDependencyInherited: 110 reasonStr = " (inherited)" 111 case moduledeps.ProviderDependencyFromState: 112 reasonStr = " (from state)" 113 } 114 node.AddNode(fmt.Sprintf("provider.%s%s%s", name, versionsStr, reasonStr)) 115 } 116 117 for _, child := range deps.Children { 118 childNode := node.AddBranch(fmt.Sprintf("module.%s", child.Name)) 119 providersCommandPopulateTreeNode(childNode, child) 120 } 121 } 122 123 const providersCommandHelp = ` 124 Usage: terraform providers [dir] 125 126 Prints out a tree of modules in the referenced configuration annotated with 127 their provider requirements. 128 129 This provides an overview of all of the provider requirements across all 130 referenced modules, as an aid to understanding why particular provider 131 plugins are needed and why particular versions are selected. 132 133 `