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