github.com/amanya/packer@v0.12.1-0.20161117214323-902ac5ab2eb6/builder/vmware/common/step_configure_vnc.go (about) 1 package common 2 3 import ( 4 "fmt" 5 "io/ioutil" 6 "log" 7 "math/rand" 8 "net" 9 "os" 10 11 "github.com/mitchellh/multistep" 12 "github.com/mitchellh/packer/packer" 13 ) 14 15 // This step configures the VM to enable the VNC server. 16 // 17 // Uses: 18 // ui packer.Ui 19 // vmx_path string 20 // 21 // Produces: 22 // vnc_port uint - The port that VNC is configured to listen on. 23 type StepConfigureVNC struct { 24 VNCBindAddress string 25 VNCPortMin uint 26 VNCPortMax uint 27 VNCDisablePassword bool 28 } 29 30 type VNCAddressFinder interface { 31 VNCAddress(string, uint, uint) (string, uint, error) 32 33 // UpdateVMX, sets driver specific VNC values to VMX data. 34 UpdateVMX(vncAddress, vncPassword string, vncPort uint, vmxData map[string]string) 35 } 36 37 func (StepConfigureVNC) VNCAddress(vncBindAddress string, portMin, portMax uint) (string, uint, error) { 38 // Find an open VNC port. Note that this can still fail later on 39 // because we have to release the port at some point. But this does its 40 // best. 41 var vncPort uint 42 portRange := int(portMax - portMin) 43 for { 44 if portRange > 0 { 45 vncPort = uint(rand.Intn(portRange)) + portMin 46 } else { 47 vncPort = portMin 48 } 49 50 log.Printf("Trying port: %d", vncPort) 51 l, err := net.Listen("tcp", fmt.Sprintf("%s:%d", vncBindAddress, vncPort)) 52 if err == nil { 53 defer l.Close() 54 break 55 } 56 } 57 return vncBindAddress, vncPort, nil 58 } 59 60 func VNCPassword(skipPassword bool) string { 61 if skipPassword { 62 return "" 63 } 64 length := int(8) 65 66 charSet := []byte("1234567890-=qwertyuiop[]asdfghjkl;zxcvbnm,./!@#%^*()_+QWERTYUIOP{}|ASDFGHJKL:XCVBNM<>?") 67 charSetLength := len(charSet) 68 69 password := make([]byte, length) 70 71 for i := 0; i < length; i++ { 72 password[i] = charSet[rand.Intn(charSetLength)] 73 } 74 75 return string(password) 76 } 77 78 func (s *StepConfigureVNC) Run(state multistep.StateBag) multistep.StepAction { 79 driver := state.Get("driver").(Driver) 80 ui := state.Get("ui").(packer.Ui) 81 vmxPath := state.Get("vmx_path").(string) 82 83 f, err := os.Open(vmxPath) 84 if err != nil { 85 err := fmt.Errorf("Error reading VMX data: %s", err) 86 state.Put("error", err) 87 ui.Error(err.Error()) 88 return multistep.ActionHalt 89 } 90 91 vmxBytes, err := ioutil.ReadAll(f) 92 if err != nil { 93 err := fmt.Errorf("Error reading VMX data: %s", err) 94 state.Put("error", err) 95 ui.Error(err.Error()) 96 return multistep.ActionHalt 97 } 98 99 var vncFinder VNCAddressFinder 100 if finder, ok := driver.(VNCAddressFinder); ok { 101 vncFinder = finder 102 } else { 103 vncFinder = s 104 } 105 log.Printf("Looking for available port between %d and %d", s.VNCPortMin, s.VNCPortMax) 106 vncBindAddress, vncPort, err := vncFinder.VNCAddress(s.VNCBindAddress, s.VNCPortMin, s.VNCPortMax) 107 if err != nil { 108 state.Put("error", err) 109 ui.Error(err.Error()) 110 return multistep.ActionHalt 111 } 112 113 vncPassword := VNCPassword(s.VNCDisablePassword) 114 115 log.Printf("Found available VNC port: %d", vncPort) 116 117 vmxData := ParseVMX(string(vmxBytes)) 118 vncFinder.UpdateVMX(vncBindAddress, vncPassword, vncPort, vmxData) 119 120 if err := WriteVMX(vmxPath, vmxData); err != nil { 121 err := fmt.Errorf("Error writing VMX data: %s", err) 122 state.Put("error", err) 123 ui.Error(err.Error()) 124 return multistep.ActionHalt 125 } 126 127 state.Put("vnc_port", vncPort) 128 state.Put("vnc_ip", vncBindAddress) 129 state.Put("vnc_password", vncPassword) 130 131 return multistep.ActionContinue 132 } 133 134 func (StepConfigureVNC) UpdateVMX(address, password string, port uint, data map[string]string) { 135 data["remotedisplay.vnc.enabled"] = "TRUE" 136 data["remotedisplay.vnc.port"] = fmt.Sprintf("%d", port) 137 data["remotedisplay.vnc.ip"] = address 138 if len(password) > 0 { 139 data["remotedisplay.vnc.password"] = password 140 } 141 } 142 143 func (StepConfigureVNC) Cleanup(multistep.StateBag) { 144 }