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