Skip to content

Commit e508cd6

Browse files
committed
Support for VBox driver
This is a legacy driver for Oracle VirtualBox, x86_64 only. It also has support for shared folders and hostonly networks, but they are not implemented just yet (sshfs and nat only) Signed-off-by: Anders F Björklund <[email protected]>
1 parent 599677f commit e508cd6

File tree

8 files changed

+389
-12
lines changed

8 files changed

+389
-12
lines changed

pkg/driverutil/instance.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,16 @@ import (
77
"github.com/lima-vm/lima/pkg/driver"
88
"github.com/lima-vm/lima/pkg/limayaml"
99
"github.com/lima-vm/lima/pkg/qemu"
10+
"github.com/lima-vm/lima/pkg/vbox"
1011
"github.com/lima-vm/lima/pkg/vz"
1112
"github.com/lima-vm/lima/pkg/wsl2"
1213
)
1314

1415
func CreateTargetDriverInstance(base *driver.BaseDriver) driver.Driver {
1516
limaDriver := base.Instance.Config.VMType
17+
if *limaDriver == limayaml.VBOX {
18+
return vbox.New(base)
19+
}
1620
if *limaDriver == limayaml.VZ {
1721
return vz.New(base)
1822
}

pkg/instance/start.go

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -402,19 +402,31 @@ func prepareDiffDisk(inst *store.Instance) error {
402402
return err
403403
}
404404

405-
f, err := os.Open(diffDisk)
406-
if err != nil {
407-
return err
408-
}
409-
defer f.Close()
405+
var diskSize int64
406+
var format string
407+
if *inst.Config.VMType != limayaml.VBOX {
408+
f, err := os.Open(diffDisk)
409+
if err != nil {
410+
return err
411+
}
412+
defer f.Close()
410413

411-
img, err := qcow2reader.Open(f)
412-
if err != nil {
413-
return err
414-
}
414+
img, err := qcow2reader.Open(f)
415+
if err != nil {
416+
return err
417+
}
415418

416-
diskSize := img.Size()
417-
format := string(img.Type())
419+
diskSize = img.Size()
420+
format = string(img.Type())
421+
} else {
422+
info, err := imgutil.GetInfo(diffDisk)
423+
if err != nil {
424+
return err
425+
}
426+
427+
diskSize = info.VSize
428+
format = info.Format
429+
}
418430

419431
if inst.Disk == diskSize {
420432
return nil

pkg/limayaml/defaults.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1110,6 +1110,8 @@ func NewArch(arch string) Arch {
11101110

11111111
func NewVMType(driver string) VMType {
11121112
switch driver {
1113+
case "vbox":
1114+
return VBOX
11131115
case "vz":
11141116
return VZ
11151117
case "qemu":

pkg/limayaml/limayaml.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ const (
8686
WSLMount MountType = "wsl2"
8787

8888
QEMU VMType = "qemu"
89+
VBOX VMType = "vbox"
8990
VZ VMType = "vz"
9091
WSL2 VMType = "wsl2"
9192
)

pkg/limayaml/validate.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,12 +84,16 @@ func Validate(y *LimaYAML, warn bool) error {
8484
// NOP
8585
case WSL2:
8686
// NOP
87+
case VBOX:
88+
if *y.Arch != X8664 {
89+
return fmt.Errorf("field `arch` must be %q for VBox; got %q", X8664, *y.Arch)
90+
}
8791
case VZ:
8892
if !IsNativeArch(*y.Arch) {
8993
return fmt.Errorf("field `arch` must be %q for VZ; got %q", NewArch(runtime.GOARCH), *y.Arch)
9094
}
9195
default:
92-
return fmt.Errorf("field `vmType` must be %q, %q, %q; got %q", QEMU, VZ, WSL2, *y.VMType)
96+
return fmt.Errorf("field `vmType` must be %q, %q, %q, or %q; got %q", QEMU, VBOX, VZ, WSL2, *y.VMType)
9397
}
9498

9599
if len(y.Images) == 0 {

pkg/qemu/imgutil/imgutil.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,11 @@ func (sp *InfoFormatSpecific) Vmdk() *InfoFormatSpecificDataVmdk {
7171
return &x
7272
}
7373

74+
func (sp *InfoFormatSpecific) Vdi() *InfoFormatSpecificDataVdi {
75+
var x InfoFormatSpecificDataVdi
76+
return &x
77+
}
78+
7479
type InfoFormatSpecificDataQcow2 struct {
7580
Compat string `json:"compat,omitempty"` // since QEMU 1.7
7681
LazyRefcounts bool `json:"lazy-refcounts,omitempty"` // since QEMU 1.7
@@ -94,6 +99,9 @@ type InfoFormatSpecificDataVmdkExtent struct {
9499
ClusterSize int `json:"cluster-size,omitempty"` // since QEMU 1.7
95100
}
96101

102+
type InfoFormatSpecificDataVdi struct {
103+
}
104+
97105
// Info corresponds to the output of `qemu-img info --output=json FILE`.
98106
type Info struct {
99107
Filename string `json:"filename,omitempty"` // since QEMU 1.3
@@ -121,6 +129,18 @@ func ConvertToRaw(source, dest string) error {
121129
return nil
122130
}
123131

132+
func ConvertToVDI(source string, dest string) error {
133+
var stdout, stderr bytes.Buffer
134+
cmd := exec.Command("qemu-img", "convert", "-O", "vdi", source, dest)
135+
cmd.Stdout = &stdout
136+
cmd.Stderr = &stderr
137+
if err := cmd.Run(); err != nil {
138+
return fmt.Errorf("failed to run %v: stdout=%q, stderr=%q: %w",
139+
cmd.Args, stdout.String(), stderr.String(), err)
140+
}
141+
return nil
142+
}
143+
124144
func ParseInfo(b []byte) (*Info, error) {
125145
var imgInfo Info
126146
if err := json.Unmarshal(b, &imgInfo); err != nil {

pkg/vbox/disk.go

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
package vbox
2+
3+
import (
4+
"context"
5+
"errors"
6+
"fmt"
7+
"os"
8+
"os/exec"
9+
"path/filepath"
10+
"strconv"
11+
12+
"github.com/docker/go-units"
13+
"github.com/lima-vm/lima/pkg/driver"
14+
"github.com/lima-vm/lima/pkg/fileutils"
15+
"github.com/lima-vm/lima/pkg/iso9660util"
16+
"github.com/lima-vm/lima/pkg/qemu/imgutil"
17+
"github.com/lima-vm/lima/pkg/store/filenames"
18+
)
19+
20+
func EnsureDisk(ctx context.Context, driver *driver.BaseDriver) error {
21+
diffDisk := filepath.Join(driver.Instance.Dir, filenames.DiffDisk)
22+
if _, err := os.Stat(diffDisk); err == nil || !errors.Is(err, os.ErrNotExist) {
23+
// disk is already ensured
24+
return err
25+
}
26+
27+
baseDisk := filepath.Join(driver.Instance.Dir, filenames.BaseDisk)
28+
if _, err := os.Stat(baseDisk); errors.Is(err, os.ErrNotExist) {
29+
var ensuredBaseDisk bool
30+
errs := make([]error, len(driver.Instance.Config.Images))
31+
for i, f := range driver.Instance.Config.Images {
32+
if _, err := fileutils.DownloadFile(ctx, baseDisk, f.File, true, "the image", *driver.Instance.Config.Arch); err != nil {
33+
errs[i] = err
34+
continue
35+
}
36+
ensuredBaseDisk = true
37+
break
38+
}
39+
if !ensuredBaseDisk {
40+
return fileutils.Errors(errs)
41+
}
42+
}
43+
diskSize, _ := units.RAMInBytes(*driver.Instance.Config.Disk)
44+
if diskSize == 0 {
45+
return nil
46+
}
47+
//TODO - Break qemu dependency
48+
isBaseDiskISO, err := iso9660util.IsISO9660(baseDisk)
49+
if err != nil {
50+
return err
51+
}
52+
baseDiskInfo, err := imgutil.GetInfo(baseDisk)
53+
if err != nil {
54+
return fmt.Errorf("failed to get the information of base disk %q: %w", baseDisk, err)
55+
}
56+
if err = imgutil.AcceptableAsBasedisk(baseDiskInfo); err != nil {
57+
return fmt.Errorf("file %q is not acceptable as the base disk: %w", baseDisk, err)
58+
}
59+
if baseDiskInfo.Format == "" {
60+
return fmt.Errorf("failed to inspect the format of %q", baseDisk)
61+
}
62+
args := []string{"create", "-f", "qcow2"}
63+
if !isBaseDiskISO {
64+
args = append(args, "-F", baseDiskInfo.Format, "-b", baseDisk)
65+
}
66+
args = append(args, diffDisk, strconv.Itoa(int(diskSize)))
67+
cmd := exec.Command("qemu-img", args...)
68+
if out, err := cmd.CombinedOutput(); err != nil {
69+
return fmt.Errorf("failed to run %v: %q: %w", cmd.Args, string(out), err)
70+
}
71+
if isBaseDiskISO {
72+
if err = os.Rename(baseDisk, baseDisk+".iso"); err != nil {
73+
return err
74+
}
75+
if err = os.Symlink(filenames.BaseDisk+".iso", baseDisk); err != nil {
76+
return err
77+
}
78+
} else {
79+
if err = os.Rename(baseDisk, baseDisk+".img"); err != nil {
80+
return err
81+
}
82+
if err = os.Symlink(filenames.BaseDisk+".img", baseDisk); err != nil {
83+
return err
84+
}
85+
}
86+
if err = imgutil.ConvertToVDI(diffDisk, diffDisk+".vdi"); err != nil {
87+
return fmt.Errorf("cannot convert qcow2 to vdi for vbox driver")
88+
}
89+
if err = os.Remove(diffDisk); err != nil {
90+
return err
91+
}
92+
return os.Symlink(filenames.DiffDisk+".vdi", diffDisk)
93+
}

0 commit comments

Comments
 (0)