diff --git a/builder/xenserver/common/proxy.go b/builder/xenserver/common/proxy.go index 6f38ac2..b217c78 100644 --- a/builder/xenserver/common/proxy.go +++ b/builder/xenserver/common/proxy.go @@ -7,6 +7,7 @@ import ( "golang.org/x/crypto/ssh" "golang.org/x/net/proxy" "io" + "log" "net" "time" ) @@ -110,8 +111,7 @@ func CreateCustomPortForwarding(connectTarget func() (net.Conn, error)) (net.Lis for { accept, err := listener.Accept() if err != nil { - fmt.Printf("error accepting: %v", err) - continue + return } go handleConnection(accept, connectTarget) @@ -128,12 +128,14 @@ func serviceForwardedConnection(clientConn net.Conn, targetConn net.Conn) { go func() { _, err := io.Copy(targetConn, clientConn) + log.Printf("[FORWARD] proxy client closed connection") + // Close conn so that other copy operation unblocks targetConn.Close() close(txDone) if err != nil { - fmt.Printf("[FORWARD] Error conn <- accept: %v", err) + log.Printf("[FORWARD] Error conn <- accept: %v", err) return } }() @@ -141,12 +143,14 @@ func serviceForwardedConnection(clientConn net.Conn, targetConn net.Conn) { go func() { _, err := io.Copy(clientConn, targetConn) + log.Printf("[FORWARD] proxy target closed connection") + // Close accept so that other copy operation unblocks clientConn.Close() close(rxDone) if err != nil { - fmt.Printf("[FORWARD] Error accept <- conn: %v", err) + log.Printf("[FORWARD] Error accept <- conn: %v", err) return } }() @@ -160,7 +164,7 @@ func handleConnection(clientConn net.Conn, connectTarget func() (net.Conn, error targetConn, err := connectTarget() if err != nil { - fmt.Printf("[FORWARD] Connect proxy Error: %v", err) + log.Printf("[FORWARD] Connect proxy Error: %v", err) return } diff --git a/builder/xenserver/common/step_get_vnc_port.go b/builder/xenserver/common/step_get_vnc_port.go index b4bac56..7e18ed3 100644 --- a/builder/xenserver/common/step_get_vnc_port.go +++ b/builder/xenserver/common/step_get_vnc_port.go @@ -1,51 +1,46 @@ package common import ( + "context" "fmt" - "strconv" - "github.com/hashicorp/packer-plugin-sdk/multistep" "github.com/hashicorp/packer-plugin-sdk/packer" + "net" ) -type StepGetVNCPort struct{} +type StepGetVNCPort struct { + listener net.Listener +} -func (self *StepGetVNCPort) Run(state multistep.StateBag) multistep.StepAction { +func (self *StepGetVNCPort) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { ui := state.Get("ui").(packer.Ui) - ui.Say("Step: forward the instances VNC port over SSH") + ui.Say("Step: forward the instances VNC") - domid := state.Get("domid").(int) - cmd := fmt.Sprintf("xenstore-read /local/domain/%d/console/vnc-port", domid) - - remote_vncport, err := ExecuteHostSSHCmd(state, cmd) + location, err := GetVNCConsoleLocation(state) if err != nil { - ui.Error(fmt.Sprintf("Unable to get VNC port (is the VM running?): %s", err.Error())) - return multistep.ActionHalt - } - - remote_port, err := strconv.ParseUint(remote_vncport, 10, 16) - - if err != nil { - ui.Error(fmt.Sprintf("Unable to convert '%s' to an int", remote_vncport)) + state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } - state.Put("instance_vnc_port", uint(remote_port)) + forwardingListener, err := CreateCustomPortForwarding(func() (net.Conn, error) { + return CreateVNCConnection(state, location) + }) + + if err != nil { + state.Put("error", err) + ui.Error(err.Error()) + return multistep.ActionHalt + } + + self.listener = forwardingListener + + ui.Say(fmt.Sprintf("VNC available on vnc://%s", self.listener.Addr().String())) return multistep.ActionContinue } func (self *StepGetVNCPort) Cleanup(state multistep.StateBag) { -} - -func InstanceVNCPort(state multistep.StateBag) (uint, error) { - vncPort := state.Get("instance_vnc_port").(uint) - return vncPort, nil -} - -func InstanceVNCIP(state multistep.StateBag) (string, error) { - // The port is in Dom0, so we want to forward from localhost - return "127.0.0.1", nil + self.listener.Close() } diff --git a/builder/xenserver/common/vnc.go b/builder/xenserver/common/vnc.go index 601774f..b817349 100644 --- a/builder/xenserver/common/vnc.go +++ b/builder/xenserver/common/vnc.go @@ -78,7 +78,7 @@ func CreateVNCClient(state multistep.StateBag, location string) (*vnc.ClientConn } client, err := vnc.Client(connection, &vnc.ClientConfig{ - Exclusive: false, + Exclusive: true, }) if err != nil { connection.Close() diff --git a/builder/xenserver/iso/builder.go b/builder/xenserver/iso/builder.go index c3b84d9..e852d9b 100644 --- a/builder/xenserver/iso/builder.go +++ b/builder/xenserver/iso/builder.go @@ -253,17 +253,14 @@ func (self *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (p new(xscommon.StepHTTPIPDiscover), &xscommon.StepCreateProxy{}, commonsteps.HTTPServerFromHTTPConfig(&self.config.HTTPConfig), - // &xscommon.StepForwardPortOverSSH{ - // RemotePort: xscommon.InstanceVNCPort, - // RemoteDest: xscommon.InstanceVNCIP, - // HostPortMin: self.config.HostPortMin, - // HostPortMax: self.config.HostPortMax, - // ResultKey: "local_vnc_port", - // }, new(xscommon.StepBootWait), &xscommon.StepTypeBootCommand{ Ctx: *self.config.GetInterpContext(), }, + /* + VNC is only available after boot command because xenserver doesn't seem to support two vnc connections at the same time + */ + &xscommon.StepGetVNCPort{}, &xscommon.StepWaitForIP{ Chan: httpReqChan, Timeout: self.config.InstallTimeout, // @todo change this diff --git a/builder/xenserver/xva/builder.go b/builder/xenserver/xva/builder.go index 47673b2..daba40c 100644 --- a/builder/xenserver/xva/builder.go +++ b/builder/xenserver/xva/builder.go @@ -151,6 +151,10 @@ func (self *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (p &xscommon.StepTypeBootCommand{ Ctx: *self.config.GetInterpContext(), }, + /* + VNC is only available after boot command because xenserver doesn't seem to support two vnc connections at the same time + */ + &xscommon.StepGetVNCPort{}, &xscommon.StepWaitForIP{ Chan: httpReqChan, Timeout: 300 * time.Minute, /*self.config.InstallTimeout*/ // @todo change this