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  }