From 23769430bbb93ebf00aaba4f8f8e923bf253cdf1 Mon Sep 17 00:00:00 2001 From: Erik Wahlberger Date: Sat, 8 Apr 2023 10:17:26 +0200 Subject: [PATCH] Add support for IP address changes This commit improves upon the existing "Wait for IP step", by continuously checking for changes to the IP address for the VM, even after the IP address has been retrieved. The implementation is using a simple goroutine which encapsulates the existing method used to wait for the IP address. When an IP address has been found, the goroutine will put the IP address directly in the state, which will be queried when the IP address should be retrieved. --- builder/xenserver/common/ssh.go | 9 +++- .../common/step_forward_port_over_ssh.go | 2 +- builder/xenserver/common/step_wait_for_ip.go | 49 ++++++++++++------- 3 files changed, 40 insertions(+), 20 deletions(-) diff --git a/builder/xenserver/common/ssh.go b/builder/xenserver/common/ssh.go index c484b31..91d9eb3 100644 --- a/builder/xenserver/common/ssh.go +++ b/builder/xenserver/common/ssh.go @@ -157,8 +157,7 @@ func forward(local_conn net.Conn, config *gossh.ClientConfig, server string, ser return nil } -func ssh_port_forward(local_listener net.Listener, remote_port int, remote_dest, host string, host_ssh_port int, username, password string) error { - +func ssh_port_forward(local_listener net.Listener, remote_port int, host string, host_ssh_port int, username, password string, remote_dest_func func() (string, error)) error { config := &gossh.ClientConfig{ User: username, Auth: []gossh.AuthMethod{ @@ -175,6 +174,12 @@ func ssh_port_forward(local_listener net.Listener, remote_port int, remote_dest, return err } + remote_dest, err := remote_dest_func() + + if err != nil { + return err + } + // Forward to a remote port go forward(local_connection, config, host, host_ssh_port, remote_dest, uint(remote_port)) } diff --git a/builder/xenserver/common/step_forward_port_over_ssh.go b/builder/xenserver/common/step_forward_port_over_ssh.go index b573443..64d5791 100644 --- a/builder/xenserver/common/step_forward_port_over_ssh.go +++ b/builder/xenserver/common/step_forward_port_over_ssh.go @@ -39,7 +39,7 @@ func (self *StepForwardPortOverSSH) Run(ctx context.Context, state multistep.Sta remotePort, _ := self.RemotePort(state) remoteDest, _ := self.RemoteDest(state) - go ssh_port_forward(l, remotePort, remoteDest, hostAddress, hostSshPort, config.Username, config.Password) + go ssh_port_forward(l, remotePort, hostAddress, hostSshPort, config.Username, config.Password, func() (string, error) { return self.RemoteDest(state) }) ui.Say(fmt.Sprintf("Port forward setup. %d ---> %s:%d on %s", sshHostPort, remoteDest, remotePort, hostAddress)) // Provide the local port to future steps. diff --git a/builder/xenserver/common/step_wait_for_ip.go b/builder/xenserver/common/step_wait_for_ip.go index bed9735..b06f9f3 100644 --- a/builder/xenserver/common/step_wait_for_ip.go +++ b/builder/xenserver/common/step_wait_for_ip.go @@ -29,47 +29,62 @@ func (self *StepWaitForIP) Run(ctx context.Context, state multistep.StateBag) mu return multistep.ActionHalt } - var ip string - err = InterruptibleWait{ - Timeout: self.Timeout, - PredicateInterval: 5 * time.Second, - Predicate: func() (result bool, err error) { + go func(c Connection, ui packer.Ui, config CommonConfig) { + state.Put("instance_ssh_address", "") + var ip string + for true { + time.Sleep(500 * time.Millisecond) if config.IPGetter == "auto" || config.IPGetter == "http" { - // Snoop IP from HTTP fetch select { - case ip = <-self.Chan: - ui.Message(fmt.Sprintf("Got IP '%s' from HTTP request", ip)) - return true, nil + case temp_ip := <-self.Chan: + if ip != temp_ip { + ip = temp_ip + ui.Message(fmt.Sprintf("Got IP '%s' from HTTP request", ip)) + state.Put("instance_ssh_address", ip) + } default: } - } if config.IPGetter == "auto" || config.IPGetter == "tools" { - // Look for PV IP m, err := c.client.VM.GetGuestMetrics(c.session, instance) if err != nil { - return false, err + continue } if m != "" { metrics, err := c.client.VMGuestMetrics.GetRecord(c.session, m) if err != nil { - return false, err + continue } networks := metrics.Networks - var ok bool - if ip, ok = networks["0/ip"]; ok { - if ip != "" { + if temp_ip, ok := networks["0/ip"]; ok { + if temp_ip != "" && ip != temp_ip { + ip = temp_ip ui.Message(fmt.Sprintf("Got IP '%s' from XenServer tools", ip)) - return true, nil + state.Put("instance_ssh_address", ip) } } } } + } + }(*c, ui, config) + + time.Sleep(500 * time.Millisecond) + + var ip string + + err = InterruptibleWait{ + Timeout: self.Timeout, + PredicateInterval: 5 * time.Second, + Predicate: func() (result bool, err error) { + var ok bool + if ip, ok = state.Get("instance_ssh_address").(string); ok && ip != "" { + return true, nil + } return false, nil },