github.com/rothwerx/packer@v0.9.0/post-processor/vsphere/post-processor.go (about)

     1  package vsphere
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"log"
     7  	"net/url"
     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 := []string{
   125  		fmt.Sprintf("--noSSLVerify=%t", p.config.Insecure),
   126  		"--acceptAllEulas",
   127  		fmt.Sprintf("--name=\"%s\"", p.config.VMName),
   128  		fmt.Sprintf("--datastore=\"%s\"", p.config.Datastore),
   129  		fmt.Sprintf("--diskMode=\"%s\"", p.config.DiskMode),
   130  		fmt.Sprintf("--network=\"%s\"", p.config.VMNetwork),
   131  		fmt.Sprintf("--vmFolder=\"%s\"", p.config.VMFolder),
   132  		fmt.Sprintf("%s", source),
   133  		fmt.Sprintf("\"%s\"", ovftool_uri),
   134  	}
   135  
   136  	ui.Message(fmt.Sprintf("Uploading %s to vSphere", source))
   137  
   138  	if p.config.Overwrite == true {
   139  		args = append(args, "--overwrite")
   140  	}
   141  
   142  	if len(p.config.Options) > 0 {
   143  		args = append(args, p.config.Options...)
   144  	}
   145  
   146  	ui.Message(fmt.Sprintf("Uploading %s to vSphere", source))
   147  	var out bytes.Buffer
   148  	log.Printf("Starting ovftool with parameters: %s", strings.Join(args, " "))
   149  	cmd := exec.Command("ovftool", args...)
   150  	cmd.Stdout = &out
   151  	if err := cmd.Run(); err != nil {
   152  		return nil, false, fmt.Errorf("Failed: %s\nStdout: %s", err, out.String())
   153  	}
   154  
   155  	ui.Message(fmt.Sprintf("%s", out.String()))
   156  
   157  	return artifact, false, nil
   158  }