github.com/rstandt/terraform@v0.12.32-0.20230710220336-b1063613405c/command/internal_plugin.go (about) 1 package command 2 3 import ( 4 "fmt" 5 "log" 6 "strings" 7 8 "github.com/hashicorp/terraform/plugin" 9 "github.com/kardianos/osext" 10 ) 11 12 // InternalPluginCommand is a Command implementation that allows plugins to be 13 // compiled into the main Terraform binary and executed via a subcommand. 14 type InternalPluginCommand struct { 15 Meta 16 } 17 18 const TFSPACE = "-TFSPACE-" 19 20 // BuildPluginCommandString builds a special string for executing internal 21 // plugins. It has the following format: 22 // 23 // /path/to/terraform-TFSPACE-internal-plugin-TFSPACE-terraform-provider-aws 24 // 25 // We split the string on -TFSPACE- to build the command executor. The reason we 26 // use -TFSPACE- is so we can support spaces in the /path/to/terraform part. 27 func BuildPluginCommandString(pluginType, pluginName string) (string, error) { 28 terraformPath, err := osext.Executable() 29 if err != nil { 30 return "", err 31 } 32 parts := []string{terraformPath, "internal-plugin", pluginType, pluginName} 33 return strings.Join(parts, TFSPACE), nil 34 } 35 36 // Internal plugins do not support any CLI args, but we do receive flags that 37 // main.go:mergeEnvArgs has merged in from EnvCLI. Instead of making main.go 38 // aware of this exception, we strip all flags from our args. Flags are easily 39 // identified by the '-' prefix, ensured by the cli package used. 40 func StripArgFlags(args []string) []string { 41 argsNoFlags := []string{} 42 for i := range args { 43 if !strings.HasPrefix(args[i], "-") { 44 argsNoFlags = append(argsNoFlags, args[i]) 45 } 46 } 47 return argsNoFlags 48 } 49 50 func (c *InternalPluginCommand) Run(args []string) int { 51 // strip flags from args, only use subcommands. 52 args = StripArgFlags(args) 53 54 if len(args) != 2 { 55 log.Printf("Wrong number of args; expected: terraform internal-plugin pluginType pluginName") 56 return 1 57 } 58 59 pluginType := args[0] 60 pluginName := args[1] 61 62 log.SetPrefix(fmt.Sprintf("%s-%s (internal) ", pluginName, pluginType)) 63 64 switch pluginType { 65 case "provisioner": 66 pluginFunc, found := InternalProvisioners[pluginName] 67 if !found { 68 log.Printf("[ERROR] Could not load provisioner: %s", pluginName) 69 return 1 70 } 71 log.Printf("[INFO] Starting provisioner plugin %s", pluginName) 72 plugin.Serve(&plugin.ServeOpts{ 73 ProvisionerFunc: pluginFunc, 74 }) 75 default: 76 log.Printf("[ERROR] Invalid plugin type %s", pluginType) 77 return 1 78 } 79 80 return 0 81 } 82 83 func (c *InternalPluginCommand) Help() string { 84 helpText := ` 85 Usage: terraform internal-plugin pluginType pluginName 86 87 Runs an internally-compiled version of a plugin from the terraform binary. 88 89 NOTE: this is an internal command and you should not call it yourself. 90 ` 91 92 return strings.TrimSpace(helpText) 93 } 94 95 func (c *InternalPluginCommand) Synopsis() string { 96 return "internal plugin command" 97 }