2014-11-18 12:18:39 -06:00
|
|
|
package xenserver
|
|
|
|
|
|
|
|
import (
|
2014-12-09 08:56:42 -06:00
|
|
|
gossh "code.google.com/p/go.crypto/ssh"
|
2014-12-08 09:34:48 -06:00
|
|
|
"fmt"
|
|
|
|
"github.com/mitchellh/multistep"
|
|
|
|
"github.com/mitchellh/packer/packer"
|
|
|
|
"log"
|
|
|
|
"time"
|
2014-11-18 12:18:39 -06:00
|
|
|
)
|
|
|
|
|
|
|
|
type stepStartOnHIMN struct{}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This step starts the installed guest on the Host Internal Management Network
|
|
|
|
* as there exists an API to obtain the IP allocated to the VM by XAPI.
|
|
|
|
* This in turn will allow Packer to SSH into the VM, provided NATing has been
|
|
|
|
* enabled on the host.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
func (self *stepStartOnHIMN) Run(state multistep.StateBag) multistep.StepAction {
|
|
|
|
|
2014-12-08 09:34:48 -06:00
|
|
|
ui := state.Get("ui").(packer.Ui)
|
|
|
|
client := state.Get("client").(XenAPIClient)
|
|
|
|
config := state.Get("config").(config)
|
2014-11-18 12:18:39 -06:00
|
|
|
|
2014-12-08 09:34:48 -06:00
|
|
|
ui.Say("Step: Start VM on the Host Internal Mangement Network")
|
2014-11-18 12:18:39 -06:00
|
|
|
|
2014-12-15 05:18:57 -06:00
|
|
|
uuid := state.Get("instance_uuid").(string)
|
|
|
|
instance, err := client.GetVMByUuid(uuid)
|
|
|
|
if err != nil {
|
|
|
|
ui.Error(fmt.Sprintf("Unable to get VM from UUID '%s': %s", uuid, err.Error()))
|
|
|
|
return multistep.ActionHalt
|
|
|
|
}
|
2014-11-18 12:18:39 -06:00
|
|
|
|
2014-12-08 09:34:48 -06:00
|
|
|
// Find the HIMN Ref
|
|
|
|
networks, err := client.GetNetworkByNameLabel("Host internal management network")
|
|
|
|
if err != nil || len(networks) == 0 {
|
2014-12-09 05:27:31 -06:00
|
|
|
ui.Error("Unable to find a host internal management network")
|
|
|
|
ui.Error(err.Error())
|
2014-12-08 09:34:48 -06:00
|
|
|
return multistep.ActionHalt
|
|
|
|
}
|
2014-11-18 12:18:39 -06:00
|
|
|
|
2014-12-08 09:34:48 -06:00
|
|
|
himn := networks[0]
|
2014-11-18 12:18:39 -06:00
|
|
|
|
2014-12-08 09:34:48 -06:00
|
|
|
// Create a VIF for the HIMN
|
|
|
|
himn_vif, err := instance.ConnectNetwork(himn, "0")
|
|
|
|
if err != nil {
|
2014-12-09 05:27:31 -06:00
|
|
|
ui.Error("Error creating VIF")
|
|
|
|
ui.Error(err.Error())
|
2014-12-08 09:34:48 -06:00
|
|
|
return multistep.ActionHalt
|
|
|
|
}
|
2014-11-18 12:18:39 -06:00
|
|
|
|
2014-12-08 09:34:48 -06:00
|
|
|
// Start the VM
|
|
|
|
instance.Start(false, false)
|
2014-11-18 12:18:39 -06:00
|
|
|
|
2014-12-08 09:34:48 -06:00
|
|
|
var himn_iface_ip string = ""
|
2014-11-18 12:18:39 -06:00
|
|
|
|
2014-12-08 09:34:48 -06:00
|
|
|
// Obtain the allocated IP
|
2014-12-09 08:56:42 -06:00
|
|
|
err = InterruptibleWait{
|
|
|
|
Predicate: func() (found bool, err error) {
|
|
|
|
ips, err := himn.GetAssignedIPs()
|
|
|
|
if err != nil {
|
|
|
|
return false, fmt.Errorf("Can't get assigned IPs: %s", err.Error())
|
|
|
|
}
|
|
|
|
log.Printf("IPs: %s", ips)
|
|
|
|
log.Printf("Ref: %s", instance.Ref)
|
|
|
|
|
|
|
|
//Check for instance.Ref in map
|
2014-12-10 04:41:59 -06:00
|
|
|
if vm_ip, ok := ips[himn_vif.Ref]; ok && vm_ip != "" {
|
2014-12-09 08:56:42 -06:00
|
|
|
ui.Say("Found the VM's IP: " + vm_ip)
|
|
|
|
himn_iface_ip = vm_ip
|
|
|
|
return true, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
ui.Say("Wait for IP address...")
|
|
|
|
return false, nil
|
|
|
|
},
|
|
|
|
PredicateInterval: 10 * time.Second,
|
|
|
|
Timeout: 100 * time.Second,
|
|
|
|
}.Wait(state)
|
|
|
|
|
2014-12-10 04:41:59 -06:00
|
|
|
if err != nil {
|
2014-12-09 08:56:42 -06:00
|
|
|
ui.Error(fmt.Sprintf("Unable to find an IP on the Host-internal management interface: %s", err.Error()))
|
|
|
|
return multistep.ActionHalt
|
2014-12-08 09:34:48 -06:00
|
|
|
}
|
2014-11-18 12:18:39 -06:00
|
|
|
|
2014-12-10 04:41:59 -06:00
|
|
|
state.Put("himn_ssh_address", himn_iface_ip)
|
|
|
|
ui.Say("Stored VM's IP " + himn_iface_ip)
|
2014-11-18 12:18:39 -06:00
|
|
|
|
2014-12-08 09:34:48 -06:00
|
|
|
// Wait for the VM to boot, and check we can ping this interface
|
2014-11-20 12:54:23 -06:00
|
|
|
|
2014-12-08 09:34:48 -06:00
|
|
|
ping_cmd := fmt.Sprintf("ping -c 1 %s", himn_iface_ip)
|
2014-11-20 12:54:23 -06:00
|
|
|
|
2014-12-09 08:56:42 -06:00
|
|
|
err = InterruptibleWait{
|
|
|
|
Predicate: func() (success bool, err error) {
|
|
|
|
ui.Message(fmt.Sprintf("Attempting to ping interface: %s", ping_cmd))
|
|
|
|
_, err = execute_ssh_cmd(ping_cmd, config.HostIp, "22", config.Username, config.Password)
|
|
|
|
|
|
|
|
switch err.(type) {
|
|
|
|
case nil:
|
|
|
|
// ping succeeded
|
|
|
|
return true, nil
|
|
|
|
case *gossh.ExitError:
|
|
|
|
// ping failed, try again
|
|
|
|
return false, nil
|
|
|
|
default:
|
|
|
|
// unknown error
|
|
|
|
return false, err
|
|
|
|
}
|
|
|
|
},
|
|
|
|
PredicateInterval: 10 * time.Second,
|
|
|
|
Timeout: 300 * time.Second,
|
|
|
|
}.Wait(state)
|
2014-11-20 12:54:23 -06:00
|
|
|
|
2014-12-08 09:34:48 -06:00
|
|
|
if err != nil {
|
2014-12-09 08:56:42 -06:00
|
|
|
ui.Error(fmt.Sprintf("Unable to ping interface. (Has the VM not booted?): %s", err.Error()))
|
2014-12-08 09:34:48 -06:00
|
|
|
return multistep.ActionHalt
|
|
|
|
}
|
2014-11-20 12:54:23 -06:00
|
|
|
|
2014-12-09 08:56:42 -06:00
|
|
|
ui.Message("Ping success! Continuing...")
|
2014-12-08 09:34:48 -06:00
|
|
|
return multistep.ActionContinue
|
2014-11-18 12:18:39 -06:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
func (self *stepStartOnHIMN) Cleanup(state multistep.StateBag) {}
|
|
|
|
|
2014-12-08 09:34:48 -06:00
|
|
|
func himnSSHIP(state multistep.StateBag) (string, error) {
|
|
|
|
ip := state.Get("himn_ssh_address").(string)
|
|
|
|
return ip, nil
|
2014-11-18 12:18:39 -06:00
|
|
|
}
|
|
|
|
|
2014-12-08 09:34:48 -06:00
|
|
|
func himnSSHPort(state multistep.StateBag) (uint, error) {
|
|
|
|
return 22, nil
|
2014-11-18 12:18:39 -06:00
|
|
|
}
|