-
Notifications
You must be signed in to change notification settings - Fork 62
/
guestprop.go
139 lines (127 loc) · 4 KB
/
guestprop.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
package virtualbox
import (
"fmt"
"log"
"regexp"
"strings"
"sync"
)
// GuestProperty holds key, value and associated flags.
type GuestProperty struct {
Name string
Value string
}
var (
getRegexp = regexp.MustCompile("(?mi)^Value: ([^,]*)$")
waitRegexp = regexp.MustCompile("^Name: ([^,]*), value: ([^,]*), flags:.*$")
)
// SetGuestProperty writes a VirtualBox guestproperty to the given value.
func SetGuestProperty(vm string, prop string, val string) error {
if Manage().isGuest() {
_, _, err := Manage().setOpts(sudo(true)).run("guestproperty", "set", prop, val)
return err
}
_, _, err := Manage().run("guestproperty", "set", vm, prop, val)
return err
}
// GetGuestProperty reads a VirtualBox guestproperty.
func GetGuestProperty(vm string, prop string) (string, error) {
var out string
var err error
if Manage().isGuest() {
out, _, err = Manage().setOpts(sudo(true)).run("guestproperty", "get", prop)
} else {
out, _, err = Manage().run("guestproperty", "get", vm, prop)
}
if err != nil {
return "", err
}
out = strings.TrimSpace(out)
Debug("out (trimmed): '%s'", out)
var match = getRegexp.FindStringSubmatch(out)
Debug("match:", match)
if len(match) != 2 {
return "", fmt.Errorf("No match with get guestproperty output")
}
return match[1], nil
}
// WaitGuestProperty blocks until a VirtualBox guestproperty is changed
//
// The key to wait for can be a fully defined key or a key wild-card (glob-pattern).
// The first returned value is the property name that was changed.
// The second returned value is the new property value,
// Deletion of the guestproperty causes WaitGuestProperty to return the
// string.
func WaitGuestProperty(vm string, prop string) (string, string, error) {
var out string
var err error
Debug("WaitGuestProperty(): wait on '%s'", prop)
if Manage().isGuest() {
_, _, err = Manage().setOpts(sudo(true)).run("guestproperty", "wait", prop)
if err != nil {
return "", "", err
}
}
out, _, err = Manage().run("guestproperty", "wait", vm, prop)
if err != nil {
log.Print(err)
return "", "", err
}
out = strings.TrimSpace(out)
Debug("WaitGuestProperty(): out (trimmed): '%s'", out)
var match = waitRegexp.FindStringSubmatch(out)
Debug("WaitGuestProperty(): match:", match)
if len(match) != 3 {
return "", "", fmt.Errorf("No match with VBoxManage wait guestproperty output")
}
return match[1], match[2], nil
}
// WaitGuestProperties wait for changes in GuestProperties
//
// WaitGetProperties wait for changes in the VirtualBox GuestProperties matching
// the given propsPattern, for the given VM. The given bool channel indicates
// caller-required closure. The optional sync.WaitGroup enabke the caller program
// to wait for Go routine completion.
//
// It returns a channel of GuestProperty objects (name-values pairs) populated
// as they change.
//
// If the bool channel is never closed, the Waiter Go routine never ends,
// but on VBoxManage error.
//
// Each GuestProperty change must be read from thwe channel before the waiter Go
// routine resumes waiting for the next matching change.
func WaitGuestProperties(vm string, propPattern string, done chan bool, wg *sync.WaitGroup) chan GuestProperty {
props := make(chan GuestProperty)
wg.Add(1)
go func() {
defer close(props)
defer wg.Done()
for {
Debug("WaitGetProperties(): waiting for: '%s' changes", propPattern)
name, value, err := WaitGuestProperty(vm, propPattern)
if err != nil {
log.Printf("WaitGetProperties(): err=%v", err)
return
}
prop := GuestProperty{name, value}
select {
case props <- prop:
Debug("WaitGetProperties(): stacked: %+v", prop)
case <-done:
Debug("WaitGetProperties(): done channel closed")
return
}
}
}()
return props
}
// DeleteGuestProperty deletes a VirtualBox guestproperty.
func DeleteGuestProperty(vm string, prop string) error {
if Manage().isGuest() {
_, _, err := Manage().setOpts(sudo(true)).run("guestproperty", "delete", prop)
return err
}
_, _, err := Manage().run("guestproperty", "delete", vm, prop)
return err
}