Commit caca5032 authored by Mitchell Hashimoto's avatar Mitchell Hashimoto

Merge pull request #1426 from jasonberanek/vnc-fixes

vmware-iso/esxi: fix multiple issues with VNC address discovery
parents cf731bf6 ebdfa2bc
...@@ -16,7 +16,6 @@ import ( ...@@ -16,7 +16,6 @@ import (
"os" "os"
"path/filepath" "path/filepath"
"strings" "strings"
"syscall"
"time" "time"
) )
...@@ -148,29 +147,57 @@ func (d *ESX5Driver) HostIP() (string, error) { ...@@ -148,29 +147,57 @@ func (d *ESX5Driver) HostIP() (string, error) {
return host, err return host, err
} }
func (d *ESX5Driver) VNCAddress(portMin, portMax uint) (string, uint) { func (d *ESX5Driver) VNCAddress(portMin, portMax uint) (string, uint, error) {
var vncPort uint var vncPort uint
// TODO(dougm) use esxcli network ip connection list
//Process ports ESXi is listening on to determine which are available
r, err := d.esxcli("network", "ip", "connection", "list")
if err != nil {
err = fmt.Errorf("Could not retrieve network information for ESXi: %v", err)
return "", 0, err
}
listenPorts := make(map[string]bool)
for record, err := r.read(); record != nil && err == nil; record, err = r.read() {
if record["State"] == "LISTEN" {
splitAddress := strings.Split(record["LocalAddress"], ":")
log.Print(splitAddress)
port := splitAddress[len(splitAddress)-1]
log.Printf("ESXi Listening on: %s", port)
listenPorts[port] = true
}
}
for port := portMin; port <= portMax; port++ { for port := portMin; port <= portMax; port++ {
if _, ok := listenPorts[fmt.Sprintf("%d", port)]; ok {
log.Printf("Port %d in use", port)
continue
}
address := fmt.Sprintf("%s:%d", d.Host, port) address := fmt.Sprintf("%s:%d", d.Host, port)
log.Printf("Trying address: %s...", address) log.Printf("Trying address: %s...", address)
l, err := net.DialTimeout("tcp", address, 1*time.Second) l, err := net.DialTimeout("tcp", address, 1*time.Second)
if err == nil { if err != nil {
log.Printf("%s in use", address) if e, ok := err.(*net.OpError); ok {
l.Close() if e.Timeout() {
} else if e, ok := err.(*net.OpError); ok { log.Printf("Timeout connecting to: %s (check firewall rules)", address)
if e.Err == syscall.ECONNREFUSED { } else {
// then port should be available for listening vncPort = port
vncPort = port break
break }
} else if e.Timeout() {
log.Printf("Timeout connecting to: %s (check firewall rules)", address)
} }
} else {
defer l.Close()
} }
} }
return d.Host, vncPort if vncPort == 0 {
err := fmt.Errorf("Unable to find available VNC port between %d and %d",
portMin, portMax)
return d.Host, vncPort, err
}
return d.Host, vncPort, nil
} }
func (d *ESX5Driver) SSHAddress(state multistep.StateBag) (string, error) { func (d *ESX5Driver) SSHAddress(state multistep.StateBag) (string, error) {
......
...@@ -24,17 +24,22 @@ import ( ...@@ -24,17 +24,22 @@ import (
type stepConfigureVNC struct{} type stepConfigureVNC struct{}
type VNCAddressFinder interface { type VNCAddressFinder interface {
VNCAddress(uint, uint) (string, uint) VNCAddress(uint, uint) (string, uint, error)
} }
func (stepConfigureVNC) VNCAddress(portMin, portMax uint) (string, uint) { func (stepConfigureVNC) VNCAddress(portMin, portMax uint) (string, uint, error) {
// Find an open VNC port. Note that this can still fail later on // Find an open VNC port. Note that this can still fail later on
// because we have to release the port at some point. But this does its // because we have to release the port at some point. But this does its
// best. // best.
var vncPort uint var vncPort uint
portRange := int(portMax - portMin) portRange := int(portMax - portMin)
for { for {
vncPort = uint(rand.Intn(portRange)) + portMin if portRange > 0 {
vncPort = uint(rand.Intn(portRange)) + portMin
} else {
vncPort = portMin
}
log.Printf("Trying port: %d", vncPort) log.Printf("Trying port: %d", vncPort)
l, err := net.Listen("tcp", fmt.Sprintf(":%d", vncPort)) l, err := net.Listen("tcp", fmt.Sprintf(":%d", vncPort))
if err == nil { if err == nil {
...@@ -42,7 +47,7 @@ func (stepConfigureVNC) VNCAddress(portMin, portMax uint) (string, uint) { ...@@ -42,7 +47,7 @@ func (stepConfigureVNC) VNCAddress(portMin, portMax uint) (string, uint) {
break break
} }
} }
return "127.0.0.1", vncPort return "127.0.0.1", vncPort, nil
} }
func (s *stepConfigureVNC) Run(state multistep.StateBag) multistep.StepAction { func (s *stepConfigureVNC) Run(state multistep.StateBag) multistep.StepAction {
...@@ -74,10 +79,8 @@ func (s *stepConfigureVNC) Run(state multistep.StateBag) multistep.StepAction { ...@@ -74,10 +79,8 @@ func (s *stepConfigureVNC) Run(state multistep.StateBag) multistep.StepAction {
vncFinder = s vncFinder = s
} }
log.Printf("Looking for available port between %d and %d", config.VNCPortMin, config.VNCPortMax) log.Printf("Looking for available port between %d and %d", config.VNCPortMin, config.VNCPortMax)
vncIp, vncPort := vncFinder.VNCAddress(config.VNCPortMin, config.VNCPortMax) vncIp, vncPort, err := vncFinder.VNCAddress(config.VNCPortMin, config.VNCPortMax)
if vncPort == 0 { if err != nil {
err := fmt.Errorf("Unable to find available VNC port between %d and %d",
config.VNCPortMin, config.VNCPortMax)
state.Put("error", err) state.Put("error", err)
ui.Error(err.Error()) ui.Error(err.Error())
return multistep.ActionHalt return multistep.ActionHalt
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment