From 6acbc91ff7d293fb3a1a5a865c6b8b98404bb4d0 Mon Sep 17 00:00:00 2001 From: "Jason A. Beranek" Date: Mon, 18 Aug 2014 20:15:15 -0500 Subject: [PATCH 1/4] vmware-iso: Fix error vnc min/max ports [GH-1288] --- builder/vmware/iso/step_configure_vnc.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/builder/vmware/iso/step_configure_vnc.go b/builder/vmware/iso/step_configure_vnc.go index 1f194be76..1d8a068c7 100644 --- a/builder/vmware/iso/step_configure_vnc.go +++ b/builder/vmware/iso/step_configure_vnc.go @@ -34,7 +34,12 @@ func (stepConfigureVNC) VNCAddress(portMin, portMax uint) (string, uint) { var vncPort uint portRange := int(portMax - portMin) 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) l, err := net.Listen("tcp", fmt.Sprintf(":%d", vncPort)) if err == nil { From 2c41d59e2109444c35f8c798bcf39a2619c59d03 Mon Sep 17 00:00:00 2001 From: "Jason A. Beranek" Date: Mon, 18 Aug 2014 20:28:25 -0500 Subject: [PATCH 2/4] vmware-iso: Update VNCAddressFinder interface to return errors from VNCAddress() --- builder/vmware/iso/driver_esx5.go | 10 ++++++++-- builder/vmware/iso/step_configure_vnc.go | 12 +++++------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/builder/vmware/iso/driver_esx5.go b/builder/vmware/iso/driver_esx5.go index c422e20c9..b96f2c940 100644 --- a/builder/vmware/iso/driver_esx5.go +++ b/builder/vmware/iso/driver_esx5.go @@ -148,7 +148,7 @@ func (d *ESX5Driver) HostIP() (string, error) { 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 // TODO(dougm) use esxcli network ip connection list for port := portMin; port <= portMax; port++ { @@ -170,7 +170,13 @@ func (d *ESX5Driver) VNCAddress(portMin, portMax uint) (string, uint) { } } - 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) { diff --git a/builder/vmware/iso/step_configure_vnc.go b/builder/vmware/iso/step_configure_vnc.go index 1d8a068c7..a09d92baa 100644 --- a/builder/vmware/iso/step_configure_vnc.go +++ b/builder/vmware/iso/step_configure_vnc.go @@ -24,10 +24,10 @@ import ( type stepConfigureVNC struct{} 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 // because we have to release the port at some point. But this does its // best. @@ -47,7 +47,7 @@ func (stepConfigureVNC) VNCAddress(portMin, portMax uint) (string, uint) { break } } - return "127.0.0.1", vncPort + return "127.0.0.1", vncPort, nil } func (s *stepConfigureVNC) Run(state multistep.StateBag) multistep.StepAction { @@ -79,10 +79,8 @@ func (s *stepConfigureVNC) Run(state multistep.StateBag) multistep.StepAction { vncFinder = s } log.Printf("Looking for available port between %d and %d", config.VNCPortMin, config.VNCPortMax) - vncIp, vncPort := vncFinder.VNCAddress(config.VNCPortMin, config.VNCPortMax) - if vncPort == 0 { - err := fmt.Errorf("Unable to find available VNC port between %d and %d", - config.VNCPortMin, config.VNCPortMax) + vncIp, vncPort, err := vncFinder.VNCAddress(config.VNCPortMin, config.VNCPortMax) + if err != nil { state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt From 93e4475d6a0f273e3a257d1912a4a9238203c3e8 Mon Sep 17 00:00:00 2001 From: "Jason A. Beranek" Date: Mon, 18 Aug 2014 21:50:48 -0500 Subject: [PATCH 3/4] vmware-iso/driver-esxi: Detect VNC in cross-platform way [GH-1372] Use VMware calls to determine ports being listened to, and determine free VNC port --- builder/vmware/iso/driver_esx5.go | 46 +++++++++++++++++++++++-------- 1 file changed, 34 insertions(+), 12 deletions(-) diff --git a/builder/vmware/iso/driver_esx5.go b/builder/vmware/iso/driver_esx5.go index b96f2c940..565fd5ee4 100644 --- a/builder/vmware/iso/driver_esx5.go +++ b/builder/vmware/iso/driver_esx5.go @@ -16,7 +16,6 @@ import ( "os" "path/filepath" "strings" - "syscall" "time" ) @@ -150,23 +149,46 @@ func (d *ESX5Driver) HostIP() (string, error) { func (d *ESX5Driver) VNCAddress(portMin, portMax uint) (string, uint, error) { 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++ { + if _, ok := listenPorts[string(port)]; ok { + log.Printf("Port %d in use", port) + continue + } address := fmt.Sprintf("%s:%d", d.Host, port) log.Printf("Trying address: %s...", address) l, err := net.DialTimeout("tcp", address, 1*time.Second) + log.Printf("Dial complete address: %s...", address) - if err == nil { - log.Printf("%s in use", address) - l.Close() - } else if e, ok := err.(*net.OpError); ok { - if e.Err == syscall.ECONNREFUSED { - // then port should be available for listening - vncPort = port - break - } else if e.Timeout() { - log.Printf("Timeout connecting to: %s (check firewall rules)", address) + if err != nil { + if e, ok := err.(*net.OpError); ok { + if e.Timeout() { + log.Printf("Timeout connecting to: %s (check firewall rules)", address) + } else { + vncPort = port + break + } } + } else { + defer l.Close() } } From ebdfa2bc56ec0354dc2accd609b27288d28d8317 Mon Sep 17 00:00:00 2001 From: "Jason A. Beranek" Date: Wed, 20 Aug 2014 20:42:05 -0500 Subject: [PATCH 4/4] vmware-iso/driver-esxi: Fix VNC detection of used ports Fixes error in earlier commit that didn't properly detect a port was listened to. --- builder/vmware/iso/driver_esx5.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/builder/vmware/iso/driver_esx5.go b/builder/vmware/iso/driver_esx5.go index 565fd5ee4..211bc119e 100644 --- a/builder/vmware/iso/driver_esx5.go +++ b/builder/vmware/iso/driver_esx5.go @@ -169,14 +169,13 @@ func (d *ESX5Driver) VNCAddress(portMin, portMax uint) (string, uint, error) { } for port := portMin; port <= portMax; port++ { - if _, ok := listenPorts[string(port)]; ok { + if _, ok := listenPorts[fmt.Sprintf("%d", port)]; ok { log.Printf("Port %d in use", port) continue } address := fmt.Sprintf("%s:%d", d.Host, port) log.Printf("Trying address: %s...", address) l, err := net.DialTimeout("tcp", address, 1*time.Second) - log.Printf("Dial complete address: %s...", address) if err != nil { if e, ok := err.(*net.OpError); ok {