Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

health based check before polling vm #52

Merged
merged 2 commits into from
Apr 8, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions hypervisor/base/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ type Hypervisor interface {

Modify(vmName string, cpus int, mem int) error

HealthCheck(vmName, property string) (*string, error)
akhiljns marked this conversation as resolved.
Show resolved Hide resolved

GetVMProperty(vmName, property string) (*string, error)

ShowGUI(vmName string) error
Expand Down Expand Up @@ -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 {
Expand Down
9 changes: 9 additions & 0 deletions hypervisor/hypervisor.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
64 changes: 47 additions & 17 deletions hypervisor/virtualbox/virtualbox.go
Original file line number Diff line number Diff line change
Expand Up @@ -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{}
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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
}
5 changes: 3 additions & 2 deletions images/download.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
22 changes: 22 additions & 0 deletions ip/ip.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"
"sort"
"strings"
"time"

"github.com/mhewedy/vermin/hypervisor"
"github.com/mhewedy/vermin/log"
Expand All @@ -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)
akhiljns marked this conversation as resolved.
Show resolved Hide resolved
for *health != "Up" {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

part of this logic is internal to VirtualBox (checking the "up" string), other part (the loop and the timeout thing) is general to all Healthchecks

I'll accept this PR and will open another PR to illustrate what I mean here ...

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
Expand Down
Loading