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.
This commit is contained in:
Erik Wahlberger 2023-04-08 10:17:26 +02:00
parent bc21b3cfac
commit 23769430bb
No known key found for this signature in database
3 changed files with 40 additions and 20 deletions

View File

@ -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))
}

View File

@ -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.

View File

@ -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
},