github.com/vijayrajah/packer@v1.3.2/post-processor/vsphere-template/post-processor.go (about) 1 package vsphere_template 2 3 import ( 4 "context" 5 "errors" 6 "fmt" 7 "net/url" 8 "strings" 9 "time" 10 11 "github.com/hashicorp/packer/builder/vmware/iso" 12 "github.com/hashicorp/packer/common" 13 "github.com/hashicorp/packer/helper/config" 14 "github.com/hashicorp/packer/helper/multistep" 15 "github.com/hashicorp/packer/packer" 16 "github.com/hashicorp/packer/post-processor/vsphere" 17 "github.com/hashicorp/packer/template/interpolate" 18 "github.com/vmware/govmomi" 19 ) 20 21 var builtins = map[string]string{ 22 vsphere.BuilderId: "vmware", 23 iso.BuilderIdESX: "vmware", 24 } 25 26 type Config struct { 27 common.PackerConfig `mapstructure:",squash"` 28 Host string `mapstructure:"host"` 29 Insecure bool `mapstructure:"insecure"` 30 Username string `mapstructure:"username"` 31 Password string `mapstructure:"password"` 32 Datacenter string `mapstructure:"datacenter"` 33 Folder string `mapstructure:"folder"` 34 35 ctx interpolate.Context 36 } 37 38 type PostProcessor struct { 39 config Config 40 url *url.URL 41 } 42 43 func (p *PostProcessor) Configure(raws ...interface{}) error { 44 err := config.Decode(&p.config, &config.DecodeOpts{ 45 Interpolate: true, 46 InterpolateContext: &p.config.ctx, 47 InterpolateFilter: &interpolate.RenderFilter{ 48 Exclude: []string{}, 49 }, 50 }, raws...) 51 52 if err != nil { 53 return err 54 } 55 56 errs := new(packer.MultiError) 57 vc := map[string]*string{ 58 "host": &p.config.Host, 59 "username": &p.config.Username, 60 "password": &p.config.Password, 61 } 62 63 for key, ptr := range vc { 64 if *ptr == "" { 65 errs = packer.MultiErrorAppend( 66 errs, fmt.Errorf("%s must be set", key)) 67 } 68 } 69 70 if p.config.Folder != "" && !strings.HasPrefix(p.config.Folder, "/") { 71 errs = packer.MultiErrorAppend( 72 errs, fmt.Errorf("Folder must be bound to the root")) 73 } 74 75 sdk, err := url.Parse(fmt.Sprintf("https://%v/sdk", p.config.Host)) 76 if err != nil { 77 errs = packer.MultiErrorAppend( 78 errs, fmt.Errorf("Error invalid vSphere sdk endpoint: %s", err)) 79 return errs 80 } 81 82 sdk.User = url.UserPassword(p.config.Username, p.config.Password) 83 p.url = sdk 84 85 if len(errs.Errors) > 0 { 86 return errs 87 } 88 return nil 89 } 90 91 func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (packer.Artifact, bool, error) { 92 if _, ok := builtins[artifact.BuilderId()]; !ok { 93 return nil, false, fmt.Errorf("The Packer vSphere Template post-processor "+ 94 "can only take an artifact from the VMware-iso builder, built on "+ 95 "ESXi (i.e. remote) or an artifact from the vSphere post-processor. "+ 96 "Artifact type %s does not fit this requirement", artifact.BuilderId()) 97 } 98 99 f := artifact.State(iso.ArtifactConfFormat) 100 k := artifact.State(iso.ArtifactConfKeepRegistered) 101 s := artifact.State(iso.ArtifactConfSkipExport) 102 103 if f != "" && k != "true" && s == "false" { 104 return nil, false, errors.New("To use this post-processor with exporting behavior you need set keep_registered as true") 105 } 106 107 // In some occasions the VM state is powered on and if we immediately try to mark as template 108 // (after the ESXi creates it) it will fail. If vSphere is given a few seconds this behavior doesn't reappear. 109 ui.Message("Waiting 10s for VMware vSphere to start") 110 time.Sleep(10 * time.Second) 111 c, err := govmomi.NewClient(context.Background(), p.url, p.config.Insecure) 112 if err != nil { 113 return nil, false, fmt.Errorf("Error connecting to vSphere: %s", err) 114 } 115 116 defer c.Logout(context.Background()) 117 118 state := new(multistep.BasicStateBag) 119 state.Put("ui", ui) 120 state.Put("client", c) 121 122 steps := []multistep.Step{ 123 &stepChooseDatacenter{ 124 Datacenter: p.config.Datacenter, 125 }, 126 &stepCreateFolder{ 127 Folder: p.config.Folder, 128 }, 129 NewStepMarkAsTemplate(artifact), 130 } 131 runner := common.NewRunnerWithPauseFn(steps, p.config.PackerConfig, ui, state) 132 runner.Run(state) 133 if rawErr, ok := state.GetOk("error"); ok { 134 return nil, false, rawErr.(error) 135 } 136 return artifact, true, nil 137 }