github.com/rahart/packer@v0.12.2-0.20161229105310-282bb6ad370f/post-processor/vsphere/post-processor.go (about)

     1  package vsphere
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"net/url"
     7  	"os"
     8  	"os/exec"
     9  	"strings"
    10  
    11  	"github.com/mitchellh/packer/common"
    12  	"github.com/mitchellh/packer/helper/config"
    13  	"github.com/mitchellh/packer/packer"
    14  	"github.com/mitchellh/packer/template/interpolate"
    15  )
    16  
    17  var builtins = map[string]string{
    18  	"mitchellh.vmware":     "vmware",
    19  	"mitchellh.vmware-esx": "vmware",
    20  }
    21  
    22  type Config struct {
    23  	common.PackerConfig `mapstructure:",squash"`
    24  
    25  	Cluster      string   `mapstructure:"cluster"`
    26  	Datacenter   string   `mapstructure:"datacenter"`
    27  	Datastore    string   `mapstructure:"datastore"`
    28  	DiskMode     string   `mapstructure:"disk_mode"`
    29  	Host         string   `mapstructure:"host"`
    30  	Insecure     bool     `mapstructure:"insecure"`
    31  	Options      []string `mapstructure:"options"`
    32  	Overwrite    bool     `mapstructure:"overwrite"`
    33  	Password     string   `mapstructure:"password"`
    34  	ResourcePool string   `mapstructure:"resource_pool"`
    35  	Username     string   `mapstructure:"username"`
    36  	VMFolder     string   `mapstructure:"vm_folder"`
    37  	VMName       string   `mapstructure:"vm_name"`
    38  	VMNetwork    string   `mapstructure:"vm_network"`
    39  
    40  	ctx interpolate.Context
    41  }
    42  
    43  type PostProcessor struct {
    44  	config Config
    45  }
    46  
    47  func (p *PostProcessor) Configure(raws ...interface{}) error {
    48  	err := config.Decode(&p.config, &config.DecodeOpts{
    49  		Interpolate:        true,
    50  		InterpolateContext: &p.config.ctx,
    51  		InterpolateFilter: &interpolate.RenderFilter{
    52  			Exclude: []string{},
    53  		},
    54  	}, raws...)
    55  	if err != nil {
    56  		return err
    57  	}
    58  
    59  	// Defaults
    60  	if p.config.DiskMode == "" {
    61  		p.config.DiskMode = "thick"
    62  	}
    63  
    64  	// Accumulate any errors
    65  	errs := new(packer.MultiError)
    66  
    67  	if _, err := exec.LookPath("ovftool"); err != nil {
    68  		errs = packer.MultiErrorAppend(
    69  			errs, fmt.Errorf("ovftool not found: %s", err))
    70  	}
    71  
    72  	// First define all our templatable parameters that are _required_
    73  	templates := map[string]*string{
    74  		"cluster":    &p.config.Cluster,
    75  		"datacenter": &p.config.Datacenter,
    76  		"diskmode":   &p.config.DiskMode,
    77  		"host":       &p.config.Host,
    78  		"password":   &p.config.Password,
    79  		"username":   &p.config.Username,
    80  		"vm_name":    &p.config.VMName,
    81  	}
    82  	for key, ptr := range templates {
    83  		if *ptr == "" {
    84  			errs = packer.MultiErrorAppend(
    85  				errs, fmt.Errorf("%s must be set", key))
    86  		}
    87  	}
    88  
    89  	if len(errs.Errors) > 0 {
    90  		return errs
    91  	}
    92  
    93  	return nil
    94  }
    95  
    96  func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (packer.Artifact, bool, error) {
    97  	if _, ok := builtins[artifact.BuilderId()]; !ok {
    98  		return nil, false, fmt.Errorf("Unknown artifact type, can't build box: %s", artifact.BuilderId())
    99  	}
   100  
   101  	source := ""
   102  	for _, path := range artifact.Files() {
   103  		if strings.HasSuffix(path, ".vmx") || strings.HasSuffix(path, ".ovf") || strings.HasSuffix(path, ".ova") {
   104  			source = path
   105  			break
   106  		}
   107  	}
   108  
   109  	if source == "" {
   110  		return nil, false, fmt.Errorf("VMX, OVF or OVA file not found")
   111  	}
   112  
   113  	ovftool_uri := fmt.Sprintf("vi://%s:%s@%s/%s/host/%s",
   114  		url.QueryEscape(p.config.Username),
   115  		url.QueryEscape(p.config.Password),
   116  		p.config.Host,
   117  		p.config.Datacenter,
   118  		p.config.Cluster)
   119  
   120  	if p.config.ResourcePool != "" {
   121  		ovftool_uri += "/Resources/" + p.config.ResourcePool
   122  	}
   123  
   124  	args, err := p.BuildArgs(source, ovftool_uri)
   125  	if err != nil {
   126  		ui.Message(fmt.Sprintf("Failed: %s\n", err))
   127  	}
   128  
   129  	ui.Message(fmt.Sprintf("Uploading %s to vSphere", source))
   130  
   131  	log.Printf("Starting ovftool with parameters: %s", strings.Join(args, " "))
   132  	cmd := exec.Command("ovftool", args...)
   133  	cmd.Stdout = os.Stdout
   134  	cmd.Stderr = os.Stderr
   135  	if err := cmd.Run(); err != nil {
   136  		return nil, false, fmt.Errorf("Failed: %s\n", err)
   137  	}
   138  
   139  	return artifact, false, nil
   140  }
   141  
   142  func (p *PostProcessor) BuildArgs(source, ovftool_uri string) ([]string, error) {
   143  	args := []string{
   144  		"--acceptAllEulas",
   145  		fmt.Sprintf(`--name=%s`, p.config.VMName),
   146  		fmt.Sprintf(`--datastore=%s`, p.config.Datastore),
   147  	}
   148  
   149  	if p.config.Insecure {
   150  		args = append(args, fmt.Sprintf(`--noSSLVerify=%t`, p.config.Insecure))
   151  	}
   152  
   153  	if p.config.DiskMode != "" {
   154  		args = append(args, fmt.Sprintf(`--diskMode=%s`, p.config.DiskMode))
   155  	}
   156  
   157  	if p.config.VMFolder != "" {
   158  		args = append(args, fmt.Sprintf(`--vmFolder=%s`, p.config.VMFolder))
   159  	}
   160  
   161  	if p.config.VMNetwork != "" {
   162  		args = append(args, fmt.Sprintf(`--network=%s`, p.config.VMNetwork))
   163  	}
   164  
   165  	if p.config.Overwrite == true {
   166  		args = append(args, "--overwrite")
   167  	}
   168  
   169  	if len(p.config.Options) > 0 {
   170  		args = append(args, p.config.Options...)
   171  	}
   172  
   173  	args = append(args, fmt.Sprintf(`%s`, source))
   174  	args = append(args, fmt.Sprintf(`%s`, ovftool_uri))
   175  
   176  	return args, nil
   177  }