Skip to content

Commit 9fe5e3a

Browse files
committed
Update for a docker driver
This commit enables a fully functioning volume driver that is able to run from VMs in VirtualBox and perform introspection necessary to issue commands to underlying VB SOAP API to perform storage orchestration for volume attachemnt.
1 parent 83f77bb commit 9fe5e3a

11 files changed

Lines changed: 954 additions & 31 deletions

File tree

vboxwebsrv/vboxwebsrv.go

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15800,7 +15800,7 @@ type IAdditionsFacility struct {
1580015800
}
1580115801

1580215802
type IMediumAttachment struct {
15803-
XMLName xml.Name `xml:"http://www.virtualbox.org/ IMediumAttachment"`
15803+
// XMLName xml.Name `xml:"http://www.virtualbox.org/ IMediumAttachment"`
1580415804

1580515805
Medium string `xml:"medium,omitempty"`
1580615806
Controller string `xml:"controller,omitempty"`
@@ -20347,6 +20347,8 @@ func (service *VboxPortType) IMachinegetMedium(request *IMachinegetMedium) (*IMa
2034720347
// - InvalidObjectFault
2034820348
// - RuntimeFault
2034920349

20350+
type Returnval *IMediumAttachment
20351+
2035020352
func (service *VboxPortType) IMachinegetMediumAttachmentsOfController(request *IMachinegetMediumAttachmentsOfController) (*IMachinegetMediumAttachmentsOfControllerResponse, error) {
2035120353
response := new(IMachinegetMediumAttachmentsOfControllerResponse)
2035220354
err := service.client.Call("", request, response)
@@ -33330,17 +33332,20 @@ func (s *SOAPClient) Call(soapAction string, request, response interface{}) erro
3333033332
encoder := xml.NewEncoder(buffer)
3333133333
//encoder.Indent(" ", " ")
3333233334

33333-
err := encoder.Encode(envelope)
33334-
if err == nil {
33335-
err = encoder.Flush()
33335+
if err := encoder.Encode(envelope); err != nil {
33336+
return err
3333633337
}
3333733338

33338-
log.Println(buffer.String())
33339-
if err != nil {
33339+
if err := encoder.Flush(); err != nil {
3334033340
return err
3334133341
}
3334233342

33343+
// log.Println(buffer.String())
33344+
3334333345
req, err := http.NewRequest("POST", s.url, buffer)
33346+
if err != nil {
33347+
return err
33348+
}
3334433349
if s.auth != nil {
3334533350
req.SetBasicAuth(s.auth.Login, s.auth.Password)
3334633351
}
@@ -33368,12 +33373,16 @@ func (s *SOAPClient) Call(soapAction string, request, response interface{}) erro
3336833373
defer res.Body.Close()
3336933374

3337033375
rawbody, err := ioutil.ReadAll(res.Body)
33376+
if err != nil {
33377+
return err
33378+
}
33379+
3337133380
if len(rawbody) == 0 {
3337233381
log.Println("empty response")
3337333382
return nil
3337433383
}
3337533384

33376-
log.Println(string(rawbody))
33385+
// log.Println(string(rawbody))
3337733386
respEnvelope := new(SOAPEnvelope)
3337833387
respEnvelope.Body = SOAPBody{Content: response}
3337933388
err = xml.Unmarshal(rawbody, respEnvelope)

virtualboxclient/hard_disk.go

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package virtualboxclient
2+
3+
type HardDisk struct {
4+
virtualbox *VirtualBox
5+
managedObjectId string
6+
}
7+
8+
type HardDisks struct {
9+
disks []*HardDisk
10+
}
11+
12+
func (h *HardDisk) getMedium() *Medium {
13+
return &Medium{virtualbox: h.virtualbox, managedObjectId: h.managedObjectId}
14+
}
15+
16+
func isSet(value string) bool {
17+
return value != ""
18+
}
19+
20+
func (hs *HardDisks) GetMedium(objectID, name string) ([]*Medium, error) {
21+
var ms []*Medium
22+
for _, hardDisk := range hs.disks {
23+
om := hardDisk.getMedium()
24+
var m *Medium
25+
if isSet(name) || isSet(objectID) {
26+
var err error
27+
m, err = om.GetIDName()
28+
if err != nil {
29+
return nil, err
30+
}
31+
}
32+
33+
if isSet(name) && m.Name != name {
34+
continue
35+
}
36+
37+
if isSet(objectID) && m.ID != objectID {
38+
continue
39+
}
40+
41+
medium, err := om.Get()
42+
if err != nil {
43+
return nil, err
44+
}
45+
ms = append(ms, medium)
46+
}
47+
48+
return ms, nil
49+
}

virtualboxclient/machine.go

Lines changed: 241 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
package virtualboxclient
22

33
import (
4+
"errors"
5+
46
"github.com/appropriate/go-virtualboxclient/vboxwebsrv"
57
)
68

79
type Machine struct {
810
virtualbox *VirtualBox
911
managedObjectId string
12+
ID string
13+
Name string
1014
}
1115

1216
func (m *Machine) GetChipsetType() (*vboxwebsrv.ChipsetType, error) {
@@ -28,6 +32,18 @@ func (m *Machine) GetMediumAttachments() ([]*vboxwebsrv.IMediumAttachment, error
2832
return nil, err // TODO: Wrap the error
2933
}
3034

35+
ret := response.Returnval
36+
return ret, nil
37+
}
38+
39+
func (m *Machine) GetMediumAttachmentsOfController(cName string) ([]*vboxwebsrv.IMediumAttachment, error) {
40+
request := vboxwebsrv.IMachinegetMediumAttachmentsOfController{This: m.managedObjectId, Name: cName}
41+
42+
response, err := m.virtualbox.IMachinegetMediumAttachmentsOfController(&request)
43+
if err != nil {
44+
return nil, err // TODO: Wrap the error
45+
}
46+
3147
return response.Returnval, nil
3248
}
3349

@@ -53,6 +69,29 @@ func (m *Machine) GetSettingsFilePath() (string, error) {
5369
return response.Returnval, nil
5470
}
5571

72+
func (m *Machine) SaveSettings() error {
73+
request := vboxwebsrv.IMachinesaveSettings{This: m.managedObjectId}
74+
75+
_, err := m.virtualbox.IMachinesaveSettings(&request)
76+
if err != nil {
77+
defer m.DiscardSettings()
78+
return err // TODO: Wrap the error
79+
}
80+
81+
return nil
82+
}
83+
84+
func (m *Machine) DiscardSettings() error {
85+
request := vboxwebsrv.IMachinediscardSettings{This: m.managedObjectId}
86+
87+
_, err := m.virtualbox.IMachinediscardSettings(&request)
88+
if err != nil {
89+
return err // TODO: Wrap the error
90+
}
91+
92+
return nil
93+
}
94+
5695
func (m *Machine) GetStorageControllers() ([]*StorageController, error) {
5796
request := vboxwebsrv.IMachinegetStorageControllers{This: m.managedObjectId}
5897

@@ -63,8 +102,209 @@ func (m *Machine) GetStorageControllers() ([]*StorageController, error) {
63102

64103
storageControllers := make([]*StorageController, len(response.Returnval))
65104
for i, oid := range response.Returnval {
66-
storageControllers[i] = &StorageController{m.virtualbox, oid}
105+
storageControllers[i] = &StorageController{virtualbox: m.virtualbox, managedObjectId: oid}
67106
}
68107

69108
return storageControllers, nil
70109
}
110+
111+
func (m *Machine) GetStorageController(name string) (*StorageController, error) {
112+
if name == "" {
113+
return nil, errors.New("storage controller name not specified")
114+
}
115+
scs, err := m.GetStorageControllers()
116+
if err != nil {
117+
return nil, err
118+
}
119+
120+
for _, sc := range scs {
121+
scName, err := sc.GetName()
122+
if err != nil {
123+
return nil, err
124+
}
125+
if scName == name {
126+
sc.Name = scName
127+
return sc, nil
128+
}
129+
}
130+
return nil, errors.New("storage controller not found")
131+
}
132+
133+
func (m *Machine) AttachDevice(medium *Medium) error {
134+
session, err := m.virtualbox.GetSession()
135+
if err != nil {
136+
return err
137+
}
138+
// defer session.Release()
139+
140+
if err := m.Lock(session, vboxwebsrv.LockTypeShared); err != nil {
141+
return err
142+
}
143+
defer m.Unlock(session)
144+
145+
sm, err := session.GetMachine()
146+
if err != nil {
147+
return err
148+
}
149+
defer sm.Release()
150+
151+
if m.virtualbox.controllerName == "" {
152+
return errors.New("missing controllerName")
153+
}
154+
155+
sc, err := sm.GetStorageController(m.virtualbox.controllerName)
156+
if err != nil {
157+
return err
158+
}
159+
160+
pn, err := sc.GetNextAvailablePort(m)
161+
if err != nil {
162+
return err
163+
}
164+
165+
pc, err := sc.GetPortCount()
166+
if err != nil {
167+
return err
168+
}
169+
170+
spc := uint32(pn) + 1
171+
if spc > pc {
172+
if err := sc.SetPortCount(spc); err != nil {
173+
return err
174+
}
175+
}
176+
177+
request := vboxwebsrv.IMachineattachDevice{
178+
This: sm.managedObjectId,
179+
Name: sc.Name,
180+
ControllerPort: pn,
181+
Device: 0,
182+
Type_: &medium.DeviceType,
183+
Medium: medium.managedObjectId,
184+
}
185+
186+
_, err = m.virtualbox.IMachineattachDevice(&request)
187+
if err != nil {
188+
return err
189+
}
190+
191+
if err := sm.SaveSettings(); err != nil {
192+
return err
193+
}
194+
195+
if err := m.Unlock(session); err != nil {
196+
return err
197+
}
198+
199+
return nil
200+
}
201+
202+
func (m *Machine) DetachDevice(medium *Medium) error {
203+
204+
session, err := m.virtualbox.GetSession()
205+
if err != nil {
206+
return err
207+
}
208+
// defer session.Release()
209+
210+
if err := m.Lock(session, vboxwebsrv.LockTypeShared); err != nil {
211+
return err
212+
}
213+
defer m.Unlock(session)
214+
215+
sm, err := session.GetMachine()
216+
if err != nil {
217+
return err
218+
}
219+
defer sm.Release()
220+
221+
mediumAttachments, err := m.GetMediumAttachments()
222+
if err != nil {
223+
return err
224+
}
225+
226+
var request *vboxwebsrv.IMachinedetachDevice
227+
for _, ma := range mediumAttachments {
228+
am := &Medium{virtualbox: m.virtualbox, managedObjectId: ma.Medium}
229+
defer am.Release()
230+
amID, err := am.GetID()
231+
if err != nil {
232+
return err
233+
}
234+
235+
if amID != medium.ID {
236+
continue
237+
}
238+
request = &vboxwebsrv.IMachinedetachDevice{
239+
This: sm.managedObjectId,
240+
Name: ma.Controller,
241+
ControllerPort: ma.Port,
242+
Device: 0,
243+
}
244+
}
245+
if request == nil {
246+
return errors.New("couldn't find attached medium")
247+
}
248+
249+
_, err = m.virtualbox.IMachinedetachDevice(request)
250+
if err != nil {
251+
return err
252+
}
253+
254+
if err := sm.SaveSettings(); err != nil {
255+
return err
256+
}
257+
258+
return nil
259+
}
260+
261+
func (m *Machine) Unlock(session *Session) error {
262+
if err := session.UnlockMachine(); err != nil {
263+
return err
264+
}
265+
return nil
266+
}
267+
268+
func (m *Machine) Lock(session *Session, lockType vboxwebsrv.LockType) error {
269+
if err := session.LockMachine(m, lockType); err != nil {
270+
return err
271+
}
272+
return nil
273+
}
274+
275+
func (m *Machine) GetID() (string, error) {
276+
request := vboxwebsrv.IMachinegetId{This: m.managedObjectId}
277+
278+
response, err := m.virtualbox.IMachinegetId(&request)
279+
if err != nil {
280+
return "", err // TODO: Wrap the error
281+
}
282+
283+
// TODO: See if we need to do anything with the response
284+
return response.Returnval, nil
285+
}
286+
287+
func (m *Machine) GetName() (string, error) {
288+
request := vboxwebsrv.IMachinegetName{This: m.managedObjectId}
289+
290+
response, err := m.virtualbox.IMachinegetName(&request)
291+
if err != nil {
292+
return "", err // TODO: Wrap the error
293+
}
294+
295+
// TODO: See if we need to do anything with the response
296+
return response.Returnval, nil
297+
}
298+
299+
func (m *Machine) Release() error {
300+
return m.virtualbox.Release(m.managedObjectId)
301+
}
302+
303+
func (m *Machine) Refresh() error {
304+
if mr, err := m.virtualbox.FindMachine(m.ID); err != nil {
305+
return err
306+
} else {
307+
m.managedObjectId = mr.managedObjectId
308+
}
309+
return nil
310+
}

0 commit comments

Comments
 (0)