From bbe247b9995d75ab1c436771a62153779adfac8a Mon Sep 17 00:00:00 2001 From: Akhil Date: Sat, 6 Apr 2024 01:23:03 +0530 Subject: [PATCH 1/2] health based check before polling vm --- hypervisor/base/types.go | 7 ++-- hypervisor/hypervisor.go | 9 ++++ hypervisor/virtualbox/virtualbox.go | 64 +++++++++++++++++++++-------- images/download.go | 5 ++- ip/ip.go | 22 ++++++++++ 5 files changed, 84 insertions(+), 23 deletions(-) diff --git a/hypervisor/base/types.go b/hypervisor/base/types.go index 268d6d7..6c6af29 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, property 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..88aee62 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, property string) (*string, error) { + h, err := detect() + if err != nil { + return nil, err + } + + return h.HealthCheck(vmName, property) +} + 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..19e45f8 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,52 @@ func (*virtualbox) Modify(vmName string, cpus int, mem int) error { return nil } -func (*virtualbox) GetVMProperty(vmName, property string) (*string, error) { - prop, ok := propertyMap[property] +func (*virtualbox) HealthCheck(vmName, healthProperty string) (*string, error) { + healthProp, ok := propertyMap[healthProperty] if !ok { - return nil, fmt.Errorf("property %s not found", property) + return nil, fmt.Errorf("property %s not found", healthProperty) } - guestProperty, err := vboxManage("guestproperty", - "enumerate", - vmName).Call() + guestProperty, err := vboxManage("guestproperty", "enumerate", vmName).Call() + if err != nil { + return nil, err + } + + index := strings.Index(guestProperty, healthProp) + if index == -1 { + return nil, fmt.Errorf("IPV4 address property not found") + } + healthCheck, err := getValueFromProperty(guestProperty, index) if err != nil { return nil, err } - time.Sleep(30 * time.Second) + return healthCheck, nil +} - index := strings.Index(guestProperty, prop) - if index == -1 { - return nil, fmt.Errorf("IP address property not found") +func (*virtualbox) GetVMProperty(vmName, ipProperty string) (*string, error) { + ipProp, ok := propertyMap[ipProperty] + if !ok { + return nil, fmt.Errorf("property %s not found", ipProperty) } - quoteIndex := strings.Index(guestProperty[index:], "'") - if quoteIndex == -1 { - return nil, fmt.Errorf("unexpected format") + guestProperty, err := vboxManage("guestproperty", "enumerate", vmName).Call() + 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:], "'")] + index := strings.Index(guestProperty, ipProp) + if index == -1 { + return nil, fmt.Errorf("IPV4 address property not found") + } + + ipAddress, err := getValueFromProperty(guestProperty, index) + if err != nil { + return nil, err + } - return &ipAddress, nil + return ipAddress, nil } func (*virtualbox) ShowGUI(vmName string) error { @@ -291,3 +309,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..7f16d30 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, "status") + 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, "status") + if err != nil { + return "", err + } + } + } + ipAddr, err := hypervisor.GetVMProperty(vmName, "ip") if err != nil { return "", err From 419c0886777f8bf6241b867686beb20a7174b08d Mon Sep 17 00:00:00 2001 From: Akhil Date: Mon, 8 Apr 2024 21:16:38 +0530 Subject: [PATCH 2/2] health checking in vbox using getvmproperty --- hypervisor/base/types.go | 2 +- hypervisor/hypervisor.go | 4 ++-- hypervisor/virtualbox/virtualbox.go | 33 ++++++++--------------------- ip/ip.go | 4 ++-- 4 files changed, 14 insertions(+), 29 deletions(-) diff --git a/hypervisor/base/types.go b/hypervisor/base/types.go index 6c6af29..20e6162 100644 --- a/hypervisor/base/types.go +++ b/hypervisor/base/types.go @@ -22,7 +22,7 @@ type Hypervisor interface { Modify(vmName string, cpus int, mem int) error - HealthCheck(vmName, property string) (*string, error) + HealthCheck(vmName string) (*string, error) GetVMProperty(vmName, property string) (*string, error) diff --git a/hypervisor/hypervisor.go b/hypervisor/hypervisor.go index 88aee62..90d8f0d 100644 --- a/hypervisor/hypervisor.go +++ b/hypervisor/hypervisor.go @@ -102,13 +102,13 @@ func GetVMProperty(vmName, property string) (*string, error) { return h.GetVMProperty(vmName, property) } -func HealthCheck(vmName, property string) (*string, error) { +func HealthCheck(vmName string) (*string, error) { h, err := detect() if err != nil { return nil, err } - return h.HealthCheck(vmName, property) + return h.HealthCheck(vmName) } func ShowGUI(vmName string) error { diff --git a/hypervisor/virtualbox/virtualbox.go b/hypervisor/virtualbox/virtualbox.go index 19e45f8..bc3a87c 100644 --- a/hypervisor/virtualbox/virtualbox.go +++ b/hypervisor/virtualbox/virtualbox.go @@ -131,23 +131,8 @@ func (*virtualbox) Modify(vmName string, cpus int, mem int) error { return nil } -func (*virtualbox) HealthCheck(vmName, healthProperty string) (*string, error) { - healthProp, ok := propertyMap[healthProperty] - if !ok { - return nil, fmt.Errorf("property %s not found", healthProperty) - } - - guestProperty, err := vboxManage("guestproperty", "enumerate", vmName).Call() - if err != nil { - return nil, err - } - - index := strings.Index(guestProperty, healthProp) - if index == -1 { - return nil, fmt.Errorf("IPV4 address property not found") - } - - healthCheck, err := getValueFromProperty(guestProperty, index) +func (*virtualbox) HealthCheck(vmName string) (*string, error) { + healthCheck, err := Instance.GetVMProperty(vmName, "status") if err != nil { return nil, err } @@ -155,10 +140,10 @@ func (*virtualbox) HealthCheck(vmName, healthProperty string) (*string, error) { return healthCheck, nil } -func (*virtualbox) GetVMProperty(vmName, ipProperty string) (*string, error) { - ipProp, ok := propertyMap[ipProperty] +func (*virtualbox) GetVMProperty(vmName, property string) (*string, error) { + prop, ok := propertyMap[property] if !ok { - return nil, fmt.Errorf("property %s not found", ipProperty) + return nil, fmt.Errorf("property %s not found", property) } guestProperty, err := vboxManage("guestproperty", "enumerate", vmName).Call() @@ -166,17 +151,17 @@ func (*virtualbox) GetVMProperty(vmName, ipProperty string) (*string, error) { return nil, err } - index := strings.Index(guestProperty, ipProp) + index := strings.Index(guestProperty, prop) if index == -1 { - return nil, fmt.Errorf("IPV4 address property not found") + return nil, fmt.Errorf(property + " property not found") } - ipAddress, err := getValueFromProperty(guestProperty, index) + propertyValue, err := getValueFromProperty(guestProperty, index) if err != nil { return nil, err } - return ipAddress, nil + return propertyValue, nil } func (*virtualbox) ShowGUI(vmName string) error { diff --git a/ip/ip.go b/ip/ip.go index 7f16d30..73134d9 100644 --- a/ip/ip.go +++ b/ip/ip.go @@ -17,7 +17,7 @@ type addr struct { func GetIpAddress(vmName string) (string, error) { - health, err := hypervisor.HealthCheck(vmName, "status") + health, err := hypervisor.HealthCheck(vmName) if err != nil { return "", err } @@ -30,7 +30,7 @@ func GetIpAddress(vmName string) (string, error) { 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, "status") + health, err = hypervisor.HealthCheck(vmName) if err != nil { return "", err }