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