github.com/mmcquillan/packer@v1.1.1-0.20171009221028-c85cf0483a5d/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/hashicorp/packer/common"
    12  	"github.com/hashicorp/packer/helper/config"
    13  	"github.com/hashicorp/packer/packer"
    14  	"github.com/hashicorp/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  	password := url.QueryEscape(p.config.Password)
   114  	ovftool_uri := fmt.Sprintf("vi://%s:%s@%s/%s/host/%s",
   115  		url.QueryEscape(p.config.Username),
   116  		password,
   117  		p.config.Host,
   118  		p.config.Datacenter,
   119  		p.config.Cluster)
   120  
   121  	if p.config.ResourcePool != "" {
   122  		ovftool_uri += "/Resources/" + p.config.ResourcePool
   123  	}
   124  
   125  	args, err := p.BuildArgs(source, ovftool_uri)
   126  	if err != nil {
   127  		ui.Message(fmt.Sprintf("Failed: %s\n", err))
   128  	}
   129  
   130  	ui.Message(fmt.Sprintf("Uploading %s to vSphere", source))
   131  
   132  	log.Printf("Starting ovftool with parameters: %s",
   133  		strings.Replace(
   134  			strings.Join(args, " "),
   135  			password,
   136  			"<password>",
   137  			-1))
   138  	cmd := exec.Command("ovftool", args...)
   139  	cmd.Stdout = os.Stdout
   140  	cmd.Stderr = os.Stderr
   141  	if err := cmd.Run(); err != nil {
   142  		return nil, false, fmt.Errorf("Failed: %s\n", err)
   143  	}
   144  
   145  	return artifact, false, nil
   146  }
   147  
   148  func (p *PostProcessor) BuildArgs(source, ovftool_uri string) ([]string, error) {
   149  	args := []string{
   150  		"--acceptAllEulas",
   151  		fmt.Sprintf(`--name=%s`, p.config.VMName),
   152  		fmt.Sprintf(`--datastore=%s`, p.config.Datastore),
   153  	}
   154  
   155  	if p.config.Insecure {
   156  		args = append(args, fmt.Sprintf(`--noSSLVerify=%t`, p.config.Insecure))
   157  	}
   158  
   159  	if p.config.DiskMode != "" {
   160  		args = append(args, fmt.Sprintf(`--diskMode=%s`, p.config.DiskMode))
   161  	}
   162  
   163  	if p.config.VMFolder != "" {
   164  		args = append(args, fmt.Sprintf(`--vmFolder=%s`, p.config.VMFolder))
   165  	}
   166  
   167  	if p.config.VMNetwork != "" {
   168  		args = append(args, fmt.Sprintf(`--network=%s`, p.config.VMNetwork))
   169  	}
   170  
   171  	if p.config.Overwrite == true {
   172  		args = append(args, "--overwrite")
   173  	}
   174  
   175  	if len(p.config.Options) > 0 {
   176  		args = append(args, p.config.Options...)
   177  	}
   178  
   179  	args = append(args, fmt.Sprintf(`%s`, source))
   180  	args = append(args, fmt.Sprintf(`%s`, ovftool_uri))
   181  
   182  	return args, nil
   183  }