Skip to content

Commit e1687e3

Browse files
committed
storage: Add reproducer for #201
At the moment, when using Code-Hex/vz like this: ``` f, err := os.OpenFile(devPath, open_flags, 0) if err != nil { return nil, fmt.Errorf("error opening file: %v", err) } attachment, err := vz.NewDiskBlockDeviceStorageDeviceAttachment(f, conf.ReadOnly, vz.DiskSynchronizationModeFull) if err != nil { _ = f.Close() return nil, fmt.Errorf("error creating disk attachment: %v", err) } ``` the developer has to know that `f` must be kept alive at least as long as the disk attachment is in use. If not, `f` will be garbage collected, its file descriptor will be closed, and the attachment becomes invalid. In this situation, the virtualization framework would return an error. This commit simply adds a test case exhibiting this problem. This will be improved in the next commits. Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
1 parent 15b346c commit e1687e3

1 file changed

Lines changed: 76 additions & 0 deletions

File tree

storage_test.go

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@ package vz_test
22

33
import (
44
"log"
5+
"os"
6+
"os/exec"
57
"path/filepath"
8+
"runtime"
69
"strings"
710
"testing"
811

@@ -103,3 +106,76 @@ func TestBlockDeviceWithCacheAndSyncMode(t *testing.T) {
103106
t.Fatalf("want state %v but got %v", vz.VirtualMachineStateRunning, got)
104107
}
105108
}
109+
110+
func TestBlockDeviceWithDeviceAttachment(t *testing.T) {
111+
if vz.Available(12) {
112+
t.Skip("vz.NewDiskImageStorageDeviceAttachmentWithCacheAndSync is supported from macOS 12")
113+
}
114+
115+
devPath := ""
116+
container := newVirtualizationMachine(t,
117+
func(vmc *vz.VirtualMachineConfiguration) error {
118+
dir := t.TempDir()
119+
path := filepath.Join(dir, "disk.img")
120+
if err := vz.CreateDiskImage(path, 512); err != nil {
121+
t.Fatal(err)
122+
}
123+
cmd := exec.Command("hdiutil", "attach", "-imagekey", "diskimage-class=CRawDiskImage", "-nomount", path)
124+
output, err := cmd.Output()
125+
if err != nil {
126+
t.Fatalf("failed to attach disk image: %v", err)
127+
}
128+
129+
outputStr := string(output)
130+
lines := strings.Split(outputStr, "\n")
131+
if len(lines) == 0 || !strings.HasPrefix(lines[0], "/dev/") {
132+
log.Printf("[%s]\n", lines)
133+
t.Fatalf("unexpected output from `hdiutil attach`")
134+
}
135+
if len(lines) != 0 && strings.HasPrefix(lines[0], "/dev/") {
136+
devPath = strings.TrimSpace(lines[0])
137+
}
138+
139+
var attachment *vz.DiskBlockDeviceStorageDeviceAttachment
140+
{
141+
dev, err := os.Open(devPath)
142+
if err != nil {
143+
t.Fatal(err)
144+
}
145+
146+
attachment, err = vz.NewDiskBlockDeviceStorageDeviceAttachment(dev, false, vz.DiskSynchronizationModeNone)
147+
if err != nil {
148+
t.Fatal(err)
149+
}
150+
}
151+
// `dev` from the block above will be garbage collected and the underlying file descriptor will be closed.
152+
// This will trigger an internal virtualization error in the subsequent code.
153+
// https://github.com/Code-Hex/vz/issues/201
154+
runtime.GC()
155+
156+
config, err := vz.NewVirtioBlockDeviceConfiguration(attachment)
157+
if err != nil {
158+
t.Fatal(err)
159+
}
160+
vmc.SetStorageDevicesVirtualMachineConfiguration([]vz.StorageDeviceConfiguration{
161+
config,
162+
})
163+
return nil
164+
},
165+
)
166+
t.Cleanup(func() {
167+
if err := container.Shutdown(); err != nil {
168+
log.Println(err)
169+
}
170+
cmd := exec.Command("hdiutil", "detach", devPath)
171+
if err := cmd.Run(); err != nil {
172+
log.Printf("hdiutil detach %s failed: %s\n", devPath, err)
173+
}
174+
})
175+
176+
vm := container.VirtualMachine
177+
178+
if got := vm.State(); vz.VirtualMachineStateRunning != got {
179+
t.Fatalf("want state %v but got %v", vz.VirtualMachineStateRunning, got)
180+
}
181+
}

0 commit comments

Comments
 (0)