diff --git a/hypervisor/base/types.go b/hypervisor/base/types.go index 268d6d7..20e6162 100644 --- a/hypervisor/base/types.go +++ b/hypervisor/base/types.go @@ -22,6 +22,8 @@ type Hypervisor interface { Modify(vmName string, cpus int, mem int) error + HealthCheck(vmName string) (*string, error) + GetVMProperty(vmName, property string) (*string, error) ShowGUI(vmName string) error @@ -85,10 +87,7 @@ func NewSubnet(anIp, netmask string) (*Subnet, error) { func (c *Subnet) HasNext() bool { max := c.start + uint32(c.Len) - if c.current < max { - return true - } - return false + return c.current < max } func (c *Subnet) Next() *Subnet { diff --git a/hypervisor/hypervisor.go b/hypervisor/hypervisor.go index 44f090f..90d8f0d 100644 --- a/hypervisor/hypervisor.go +++ b/hypervisor/hypervisor.go @@ -102,6 +102,15 @@ func GetVMProperty(vmName, property string) (*string, error) { return h.GetVMProperty(vmName, property) } +func HealthCheck(vmName string) (*string, error) { + h, err := detect() + if err != nil { + return nil, err + } + + return h.HealthCheck(vmName) +} + func ShowGUI(vmName string) error { h, err := detect() if err != nil { diff --git a/hypervisor/virtualbox/virtualbox.go b/hypervisor/virtualbox/virtualbox.go index 72828f6..bc3a87c 100644 --- a/hypervisor/virtualbox/virtualbox.go +++ b/hypervisor/virtualbox/virtualbox.go @@ -16,10 +16,12 @@ import ( const ( ipProperty = "/VirtualBox/GuestInfo/Net/0/V4/IP" + vmStatus = "/VirtualBox/GuestInfo/Net/0/Status" ) var propertyMap = map[string]string{ - "ip": ipProperty, + "ip": ipProperty, + "status": vmStatus, } var Instance = &virtualbox{} @@ -129,36 +131,37 @@ func (*virtualbox) Modify(vmName string, cpus int, mem int) error { return nil } +func (*virtualbox) HealthCheck(vmName string) (*string, error) { + healthCheck, err := Instance.GetVMProperty(vmName, "status") + if err != nil { + return nil, err + } + + return healthCheck, nil +} + func (*virtualbox) GetVMProperty(vmName, property string) (*string, error) { prop, ok := propertyMap[property] if !ok { return nil, fmt.Errorf("property %s not found", property) } - guestProperty, err := vboxManage("guestproperty", - "enumerate", - vmName).Call() - + guestProperty, err := vboxManage("guestproperty", "enumerate", vmName).Call() if err != nil { return nil, err } - time.Sleep(30 * time.Second) - index := strings.Index(guestProperty, prop) if index == -1 { - return nil, fmt.Errorf("IP address property not found") + return nil, fmt.Errorf(property + " property not found") } - quoteIndex := strings.Index(guestProperty[index:], "'") - if quoteIndex == -1 { - return nil, fmt.Errorf("unexpected format") + propertyValue, err := getValueFromProperty(guestProperty, index) + if err != nil { + return nil, err } - // Extract the IP address between single quotes - ipAddress := guestProperty[index+quoteIndex+1 : index+quoteIndex+1+strings.Index(guestProperty[index+quoteIndex+1:], "'")] - - return &ipAddress, nil + return propertyValue, nil } func (*virtualbox) ShowGUI(vmName string) error { @@ -291,3 +294,15 @@ func (*virtualbox) GetSubnet() (*base.Subnet, error) { return base.NewSubnet(bridgeInfo[0], bridgeInfo[1]) } + +func getValueFromProperty(guestProperty string, index int) (*string, error) { + quoteIndex := strings.Index(guestProperty[index:], "'") + if quoteIndex == -1 { + return nil, fmt.Errorf("unexpected format") + } + + // Extract the IP address between single quotes + value := guestProperty[index+quoteIndex+1 : index+quoteIndex+1+strings.Index(guestProperty[index+quoteIndex+1:], "'")] + + return &value, nil +} diff --git a/images/download.go b/images/download.go index 0467026..be4c87f 100644 --- a/images/download.go +++ b/images/download.go @@ -2,13 +2,14 @@ package images import ( "fmt" - "github.com/mhewedy/vermin/images/vagrant" - "github.com/schollz/progressbar/v3" "io" "io/ioutil" "net/http" "os" "strings" + + "github.com/mhewedy/vermin/images/vagrant" + "github.com/schollz/progressbar/v3" ) type image struct { diff --git a/ip/ip.go b/ip/ip.go index 775e6d6..73134d9 100644 --- a/ip/ip.go +++ b/ip/ip.go @@ -4,6 +4,7 @@ import ( "fmt" "sort" "strings" + "time" "github.com/mhewedy/vermin/hypervisor" "github.com/mhewedy/vermin/log" @@ -15,6 +16,27 @@ type addr struct { } func GetIpAddress(vmName string) (string, error) { + + health, err := hypervisor.HealthCheck(vmName) + if err != nil { + return "", err + } + + // Wait for health status to be "Up" for up to 5 minutes + timeout := time.After(5 * time.Minute) + for *health != "Up" { + select { + case <-timeout: + return "", fmt.Errorf("timeout waiting for VM health status to be 'Up'") + default: + time.Sleep(10 * time.Second) // Check every 10 seconds + health, err = hypervisor.HealthCheck(vmName) + if err != nil { + return "", err + } + } + } + ipAddr, err := hypervisor.GetVMProperty(vmName, "ip") if err != nil { return "", err