github.com/sneal/packer@v0.5.2/builder/vmware/iso/step_configure_vnc.go (about)

     1  package iso
     2  
     3  import (
     4  	"fmt"
     5  	"github.com/mitchellh/multistep"
     6  	vmwcommon "github.com/mitchellh/packer/builder/vmware/common"
     7  	"github.com/mitchellh/packer/packer"
     8  	"io/ioutil"
     9  	"log"
    10  	"math/rand"
    11  	"net"
    12  	"os"
    13  )
    14  
    15  // This step configures the VM to enable the VNC server.
    16  //
    17  // Uses:
    18  //   config *config
    19  //   ui     packer.Ui
    20  //   vmx_path string
    21  //
    22  // Produces:
    23  //   vnc_port uint - The port that VNC is configured to listen on.
    24  type stepConfigureVNC struct{}
    25  
    26  type VNCAddressFinder interface {
    27  	VNCAddress(uint, uint) (string, uint)
    28  }
    29  
    30  func (stepConfigureVNC) VNCAddress(portMin, portMax uint) (string, uint) {
    31  	// Find an open VNC port. Note that this can still fail later on
    32  	// because we have to release the port at some point. But this does its
    33  	// best.
    34  	var vncPort uint
    35  	portRange := int(portMax - portMin)
    36  	for {
    37  		vncPort = uint(rand.Intn(portRange)) + portMin
    38  		log.Printf("Trying port: %d", vncPort)
    39  		l, err := net.Listen("tcp", fmt.Sprintf(":%d", vncPort))
    40  		if err == nil {
    41  			defer l.Close()
    42  			break
    43  		}
    44  	}
    45  	return "127.0.0.1", vncPort
    46  }
    47  
    48  func (s *stepConfigureVNC) Run(state multistep.StateBag) multistep.StepAction {
    49  	config := state.Get("config").(*config)
    50  	driver := state.Get("driver").(vmwcommon.Driver)
    51  	ui := state.Get("ui").(packer.Ui)
    52  	vmxPath := state.Get("vmx_path").(string)
    53  
    54  	f, err := os.Open(vmxPath)
    55  	if err != nil {
    56  		err := fmt.Errorf("Error reading VMX data: %s", err)
    57  		state.Put("error", err)
    58  		ui.Error(err.Error())
    59  		return multistep.ActionHalt
    60  	}
    61  
    62  	vmxBytes, err := ioutil.ReadAll(f)
    63  	if err != nil {
    64  		err := fmt.Errorf("Error reading VMX data: %s", err)
    65  		state.Put("error", err)
    66  		ui.Error(err.Error())
    67  		return multistep.ActionHalt
    68  	}
    69  
    70  	var vncFinder VNCAddressFinder
    71  	if finder, ok := driver.(VNCAddressFinder); ok {
    72  		vncFinder = finder
    73  	} else {
    74  		vncFinder = s
    75  	}
    76  	log.Printf("Looking for available port between %d and %d", config.VNCPortMin, config.VNCPortMax)
    77  	vncIp, vncPort := vncFinder.VNCAddress(config.VNCPortMin, config.VNCPortMax)
    78  	if vncPort == 0 {
    79  		err := fmt.Errorf("Unable to find available VNC port between %d and %d",
    80  			config.VNCPortMin, config.VNCPortMax)
    81  		state.Put("error", err)
    82  		ui.Error(err.Error())
    83  		return multistep.ActionHalt
    84  	}
    85  
    86  	log.Printf("Found available VNC port: %d", vncPort)
    87  
    88  	vmxData := vmwcommon.ParseVMX(string(vmxBytes))
    89  	vmxData["remotedisplay.vnc.enabled"] = "TRUE"
    90  	vmxData["remotedisplay.vnc.port"] = fmt.Sprintf("%d", vncPort)
    91  
    92  	if err := vmwcommon.WriteVMX(vmxPath, vmxData); err != nil {
    93  		err := fmt.Errorf("Error writing VMX data: %s", err)
    94  		state.Put("error", err)
    95  		ui.Error(err.Error())
    96  		return multistep.ActionHalt
    97  	}
    98  
    99  	state.Put("vnc_port", vncPort)
   100  	state.Put("vnc_ip", vncIp)
   101  
   102  	return multistep.ActionContinue
   103  }
   104  
   105  func (stepConfigureVNC) Cleanup(multistep.StateBag) {
   106  }