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