github.com/jerryclinesmith/packer@v0.3.7/config.go (about) 1 package main 2 3 import ( 4 "encoding/json" 5 "github.com/mitchellh/osext" 6 "github.com/mitchellh/packer/packer" 7 "github.com/mitchellh/packer/packer/plugin" 8 "io" 9 "log" 10 "os/exec" 11 "path/filepath" 12 ) 13 14 // This is the default, built-in configuration that ships with 15 // Packer. 16 const defaultConfig = ` 17 { 18 "plugin_min_port": 10000, 19 "plugin_max_port": 25000, 20 21 "builders": { 22 "amazon-ebs": "packer-builder-amazon-ebs", 23 "amazon-chroot": "packer-builder-amazon-chroot", 24 "amazon-instance": "packer-builder-amazon-instance", 25 "digitalocean": "packer-builder-digitalocean", 26 "openstack": "packer-builder-openstack", 27 "virtualbox": "packer-builder-virtualbox", 28 "vmware": "packer-builder-vmware" 29 }, 30 31 "commands": { 32 "build": "packer-command-build", 33 "fix": "packer-command-fix", 34 "inspect": "packer-command-inspect", 35 "validate": "packer-command-validate" 36 }, 37 38 "post-processors": { 39 "vagrant": "packer-post-processor-vagrant" 40 }, 41 42 "provisioners": { 43 "chef-solo": "packer-provisioner-chef-solo", 44 "file": "packer-provisioner-file", 45 "puppet-masterless": "packer-provisioner-puppet-masterless", 46 "shell": "packer-provisioner-shell", 47 "salt-masterless": "packer-provisioner-salt-masterless" 48 } 49 } 50 ` 51 52 type config struct { 53 PluginMinPort uint 54 PluginMaxPort uint 55 56 Builders map[string]string 57 Commands map[string]string 58 PostProcessors map[string]string `json:"post-processors"` 59 Provisioners map[string]string 60 } 61 62 // Decodes configuration in JSON format from the given io.Reader into 63 // the config object pointed to. 64 func decodeConfig(r io.Reader, c *config) error { 65 decoder := json.NewDecoder(r) 66 return decoder.Decode(c) 67 } 68 69 // Returns an array of defined command names. 70 func (c *config) CommandNames() (result []string) { 71 result = make([]string, 0, len(c.Commands)) 72 for name := range c.Commands { 73 result = append(result, name) 74 } 75 return 76 } 77 78 // This is a proper packer.BuilderFunc that can be used to load packer.Builder 79 // implementations from the defined plugins. 80 func (c *config) LoadBuilder(name string) (packer.Builder, error) { 81 log.Printf("Loading builder: %s\n", name) 82 bin, ok := c.Builders[name] 83 if !ok { 84 log.Printf("Builder not found: %s\n", name) 85 return nil, nil 86 } 87 88 return c.pluginClient(bin).Builder() 89 } 90 91 // This is a proper packer.CommandFunc that can be used to load packer.Command 92 // implementations from the defined plugins. 93 func (c *config) LoadCommand(name string) (packer.Command, error) { 94 log.Printf("Loading command: %s\n", name) 95 bin, ok := c.Commands[name] 96 if !ok { 97 log.Printf("Command not found: %s\n", name) 98 return nil, nil 99 } 100 101 return c.pluginClient(bin).Command() 102 } 103 104 // This is a proper implementation of packer.HookFunc that can be used 105 // to load packer.Hook implementations from the defined plugins. 106 func (c *config) LoadHook(name string) (packer.Hook, error) { 107 log.Printf("Loading hook: %s\n", name) 108 return c.pluginClient(name).Hook() 109 } 110 111 // This is a proper packer.PostProcessorFunc that can be used to load 112 // packer.PostProcessor implementations from defined plugins. 113 func (c *config) LoadPostProcessor(name string) (packer.PostProcessor, error) { 114 log.Printf("Loading post-processor: %s", name) 115 bin, ok := c.PostProcessors[name] 116 if !ok { 117 log.Printf("Post-processor not found: %s", name) 118 return nil, nil 119 } 120 121 return c.pluginClient(bin).PostProcessor() 122 } 123 124 // This is a proper packer.ProvisionerFunc that can be used to load 125 // packer.Provisioner implementations from defined plugins. 126 func (c *config) LoadProvisioner(name string) (packer.Provisioner, error) { 127 log.Printf("Loading provisioner: %s\n", name) 128 bin, ok := c.Provisioners[name] 129 if !ok { 130 log.Printf("Provisioner not found: %s\n", name) 131 return nil, nil 132 } 133 134 return c.pluginClient(bin).Provisioner() 135 } 136 137 func (c *config) pluginClient(path string) *plugin.Client { 138 originalPath := path 139 140 // First attempt to find the executable by consulting the PATH. 141 path, err := exec.LookPath(path) 142 if err != nil { 143 // If that doesn't work, look for it in the same directory 144 // as the `packer` executable (us). 145 log.Printf("Plugin could not be found. Checking same directory as executable.") 146 exePath, err := osext.Executable() 147 if err != nil { 148 log.Printf("Couldn't get current exe path: %s", err) 149 } else { 150 log.Printf("Current exe path: %s", exePath) 151 path = filepath.Join(filepath.Dir(exePath), filepath.Base(originalPath)) 152 } 153 } 154 155 // If everything failed, just use the original path and let the error 156 // bubble through. 157 if path == "" { 158 path = originalPath 159 } 160 161 log.Printf("Creating plugin client for path: %s", path) 162 var config plugin.ClientConfig 163 config.Cmd = exec.Command(path) 164 config.Managed = true 165 config.MinPort = c.PluginMinPort 166 config.MaxPort = c.PluginMaxPort 167 return plugin.NewClient(&config) 168 }