From 1c4321a50354cdb92ddfca0e69d142cf8a37fc3c Mon Sep 17 00:00:00 2001 From: Armon Dadgar Date: Wed, 9 Jul 2014 14:47:37 -0700 Subject: [PATCH] Setup provisioners for CLI --- config.go | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- main.go | 1 + 2 files changed, 73 insertions(+), 1 deletion(-) diff --git a/config.go b/config.go index c3cfb0f9f..b616414d7 100644 --- a/config.go +++ b/config.go @@ -16,7 +16,8 @@ import ( // This is not the configuration for Terraform itself. That is in the // "config" package. type Config struct { - Providers map[string]string + Providers map[string]string + Provisioners map[string]string } // BuiltinConfig is the built-in defaults for the configuration. These @@ -34,6 +35,9 @@ func init() { BuiltinConfig.Providers = map[string]string{ "aws": "terraform-provider-aws", } + BuiltinConfig.Provisioners = map[string]string{ + "local-exec": "terraform-provisioner-local-exec", + } } // LoadConfig loads the CLI configuration from ".terraformrc" files. @@ -69,12 +73,19 @@ func LoadConfig(path string) (*Config, error) { func (c1 *Config) Merge(c2 *Config) *Config { var result Config result.Providers = make(map[string]string) + result.Provisioners = make(map[string]string) for k, v := range c1.Providers { result.Providers[k] = v } for k, v := range c2.Providers { result.Providers[k] = v } + for k, v := range c1.Provisioners { + result.Provisioners[k] = v + } + for k, v := range c2.Provisioners { + result.Provisioners[k] = v + } return &result } @@ -138,3 +149,63 @@ func (c *Config) providerFactory(path string) terraform.ResourceProviderFactory }, nil } } + +// ProvisionerFactories returns the mapping of prefixes to +// ResourceProvisionerFactory that can be used to instantiate a +// binary-based plugin. +func (c *Config) ProvisionerFactories() map[string]terraform.ResourceProvisionerFactory { + result := make(map[string]terraform.ResourceProvisionerFactory) + for k, v := range c.Provisioners { + result[k] = c.provisionerFactory(v) + } + + return result +} + +func (c *Config) provisionerFactory(path string) terraform.ResourceProvisionerFactory { + originalPath := path + + return func() (terraform.ResourceProvisioner, error) { + // First look for the provider on the PATH. + path, err := exec.LookPath(path) + if err != nil { + // If that doesn't work, look for it in the same directory + // as the executable that is running. + exePath, err := osext.Executable() + if err == nil { + path = filepath.Join( + filepath.Dir(exePath), + filepath.Base(originalPath)) + } + } + + // If we still don't have a path set, then set it to the + // original path and let any errors that happen bubble out. + if path == "" { + path = originalPath + } + + // Build the plugin client configuration and init the plugin + var config plugin.ClientConfig + config.Cmd = exec.Command(path) + config.Managed = true + client := plugin.NewClient(&config) + + // Request the RPC client and service name from the client + // so we can build the actual RPC-implemented provider. + rpcClient, err := client.Client() + if err != nil { + return nil, err + } + + service, err := client.Service() + if err != nil { + return nil, err + } + + return &rpc.ResourceProvisioner{ + Client: rpcClient, + Name: service, + }, nil + } +} diff --git a/main.go b/main.go index c47ecca55..49331e192 100644 --- a/main.go +++ b/main.go @@ -85,6 +85,7 @@ func wrappedMain() int { // Initialize the TFConfig settings for the commands... ContextOpts.Providers = config.ProviderFactories() + ContextOpts.Provisioners = config.ProvisionerFactories() // Get the command line args. We shortcut "--version" and "-v" to // just show the version.