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