Skip to content

Commit 70c7919

Browse files
committed
defined a common interface for nativeimgutil & qemuimgutil
Signed-off-by: Praful Khanduri <[email protected]>
1 parent dbf3cd9 commit 70c7919

File tree

12 files changed

+280
-111
lines changed

12 files changed

+280
-111
lines changed

cmd/limactl/disk.go

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,7 @@ import (
1818
"github.com/sirupsen/logrus"
1919
"github.com/spf13/cobra"
2020

21-
"github.com/lima-vm/lima/pkg/nativeimgutil"
22-
"github.com/lima-vm/lima/pkg/qemu/imgutil"
21+
"github.com/lima-vm/lima/pkg/imgutil/proxyimgutil"
2322
"github.com/lima-vm/lima/pkg/store"
2423
"github.com/lima-vm/lima/pkg/store/filenames"
2524
)
@@ -113,11 +112,8 @@ func diskCreateAction(cmd *cobra.Command, args []string) error {
113112

114113
// qemu may not be available, use it only if needed.
115114
dataDisk := filepath.Join(diskDir, filenames.DataDisk)
116-
if format == "raw" {
117-
err = nativeimgutil.CreateRawDisk(dataDisk, int(diskSize))
118-
} else {
119-
err = imgutil.CreateDisk(dataDisk, format, int(diskSize))
120-
}
115+
diskUtil := proxyimgutil.NewDiskUtil()
116+
err = diskUtil.CreateDisk(dataDisk, diskSize)
121117
if err != nil {
122118
rerr := os.RemoveAll(diskDir)
123119
if rerr != nil {
@@ -410,11 +406,8 @@ func diskResizeAction(cmd *cobra.Command, args []string) error {
410406

411407
// qemu may not be available, use it only if needed.
412408
dataDisk := filepath.Join(disk.Dir, filenames.DataDisk)
413-
if disk.Format == "raw" {
414-
err = nativeimgutil.ResizeRawDisk(dataDisk, int(diskSize))
415-
} else {
416-
err = imgutil.ResizeDisk(dataDisk, disk.Format, int(diskSize))
417-
}
409+
diskUtil := proxyimgutil.NewDiskUtil()
410+
err = diskUtil.ResizeDisk(dataDisk, diskSize)
418411
if err != nil {
419412
return fmt.Errorf("failed to resize disk %q: %w", diskName, err)
420413
}

pkg/imgutil/manager.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// SPDX-FileCopyrightText: Copyright The Lima Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package imgutil
5+
6+
import (
7+
"os"
8+
)
9+
10+
// ImageDiskManager defines the common operations for disk image utilities.
11+
type ImageDiskManager interface {
12+
// CreateDisk creates a new disk image with the specified size.
13+
CreateDisk(disk string, size int64) error
14+
15+
// ResizeDisk resizes an existing disk image to the specified size.
16+
ResizeDisk(disk string, size int64) error
17+
18+
// ConvertToRaw converts a disk image to raw format.
19+
ConvertToRaw(source, dest string, size *int64, allowSourceWithBackingFile bool) error
20+
21+
// MakeSparse makes a file sparse, starting from the specified offset.
22+
MakeSparse(f *os.File, offset int64) error
23+
}

pkg/nativeimgutil/fuzz_test.go renamed to pkg/imgutil/nativeimgutil/fuzz_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,6 @@ func FuzzConvertToRaw(f *testing.F) {
1717
destPath := filepath.Join(t.TempDir(), "dest.img")
1818
err := os.WriteFile(srcPath, imgData, 0o600)
1919
assert.NilError(t, err)
20-
_ = ConvertToRaw(srcPath, destPath, &size, withBacking)
20+
_ = convertToRaw(srcPath, destPath, &size, withBacking)
2121
})
2222
}

pkg/nativeimgutil/nativeimgutil.go renamed to pkg/imgutil/nativeimgutil/nativeimgutil.go

Lines changed: 44 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -28,36 +28,19 @@ import (
2828
// aligned to 512 bytes.
2929
const sectorSize = 512
3030

31-
// RoundUp rounds size up to sectorSize.
32-
func RoundUp(size int) int {
31+
// NativeImageUtil is the native implementation of the imgutil.ImageDiskManager.
32+
type NativeImageUtil struct{}
33+
34+
// roundUp rounds size up to sectorSize.
35+
func roundUp(size int64) int64 {
3336
sectors := (size + sectorSize - 1) / sectorSize
3437
return sectors * sectorSize
3538
}
3639

37-
// CreateRawDisk creates an empty raw data disk.
38-
func CreateRawDisk(disk string, size int) error {
39-
if _, err := os.Stat(disk); err == nil || !errors.Is(err, fs.ErrNotExist) {
40-
return err
41-
}
42-
f, err := os.Create(disk)
43-
if err != nil {
44-
return err
45-
}
46-
defer f.Close()
47-
roundedSize := RoundUp(size)
48-
return f.Truncate(int64(roundedSize))
49-
}
50-
51-
// ResizeRawDisk resizes a raw data disk.
52-
func ResizeRawDisk(disk string, size int) error {
53-
roundedSize := RoundUp(size)
54-
return os.Truncate(disk, int64(roundedSize))
55-
}
56-
57-
// ConvertToRaw converts a source disk into a raw disk.
40+
// convertToRaw converts a source disk into a raw disk.
5841
// source and dest may be same.
59-
// ConvertToRaw is a NOP if source == dest, and no resizing is needed.
60-
func ConvertToRaw(source, dest string, size *int64, allowSourceWithBackingFile bool) error {
42+
// convertToRaw is a NOP if source == dest, and no resizing is needed.
43+
func convertToRaw(source, dest string, size *int64, allowSourceWithBackingFile bool) error {
6144
srcF, err := os.Open(source)
6245
if err != nil {
6346
return err
@@ -106,7 +89,7 @@ func ConvertToRaw(source, dest string, size *int64, allowSourceWithBackingFile b
10689
// Truncating before copy eliminates the seeks during copy and provide a
10790
// hint to the file system that may minimize allocations and fragmentation
10891
// of the file.
109-
if err := MakeSparse(destTmpF, srcImg.Size()); err != nil {
92+
if err := makeSparse(destTmpF, srcImg.Size()); err != nil {
11093
return err
11194
}
11295

@@ -125,7 +108,7 @@ func ConvertToRaw(source, dest string, size *int64, allowSourceWithBackingFile b
125108
// Resize
126109
if size != nil {
127110
logrus.Infof("Expanding to %s", units.BytesSize(float64(*size)))
128-
if err = MakeSparse(destTmpF, *size); err != nil {
111+
if err = makeSparse(destTmpF, *size); err != nil {
129112
return err
130113
}
131114
}
@@ -153,7 +136,7 @@ func convertRawToRaw(source, dest string, size *int64) error {
153136
if err != nil {
154137
return err
155138
}
156-
if err = MakeSparse(destF, *size); err != nil {
139+
if err = makeSparse(destF, *size); err != nil {
157140
_ = destF.Close()
158141
return err
159142
}
@@ -162,9 +145,39 @@ func convertRawToRaw(source, dest string, size *int64) error {
162145
return nil
163146
}
164147

165-
func MakeSparse(f *os.File, n int64) error {
166-
if _, err := f.Seek(n, io.SeekStart); err != nil {
148+
func makeSparse(f *os.File, offset int64) error {
149+
if _, err := f.Seek(offset, io.SeekStart); err != nil {
167150
return err
168151
}
169-
return f.Truncate(n)
152+
return f.Truncate(offset)
153+
}
154+
155+
// CreateDisk creates a new disk image with the specified size.
156+
func (n *NativeImageUtil) CreateDisk(disk string, size int64) error {
157+
if _, err := os.Stat(disk); err == nil || !errors.Is(err, fs.ErrNotExist) {
158+
return err
159+
}
160+
f, err := os.Create(disk)
161+
if err != nil {
162+
return err
163+
}
164+
defer f.Close()
165+
roundedSize := roundUp(size)
166+
return f.Truncate(int64(roundedSize))
167+
}
168+
169+
// ConvertToRaw converts a disk image to raw format.
170+
func (n *NativeImageUtil) ConvertToRaw(source, dest string, size *int64, allowSourceWithBackingFile bool) error {
171+
return convertToRaw(source, dest, size, allowSourceWithBackingFile)
172+
}
173+
174+
// ResizeDisk resizes an existing disk image to the specified size.
175+
func (n *NativeImageUtil) ResizeDisk(disk string, size int64) error {
176+
roundedSize := roundUp(size)
177+
return os.Truncate(disk, roundedSize)
178+
}
179+
180+
// MakeSparse makes a file sparse, starting from the specified offset.
181+
func (n *NativeImageUtil) MakeSparse(f *os.File, offset int64) error {
182+
return makeSparse(f, offset)
170183
}

pkg/nativeimgutil/nativeimgutil_test.go renamed to pkg/imgutil/nativeimgutil/nativeimgutil_test.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ import (
1515

1616
func TestRoundUp(t *testing.T) {
1717
tests := []struct {
18-
Size int
19-
Rounded int
18+
Size int64
19+
Rounded int64
2020
}{
2121
{0, 0},
2222
{1, 512},
@@ -25,7 +25,7 @@ func TestRoundUp(t *testing.T) {
2525
{123456789, 123457024},
2626
}
2727
for _, tc := range tests {
28-
if RoundUp(tc.Size) != tc.Rounded {
28+
if roundUp(tc.Size) != tc.Rounded {
2929
t.Errorf("expected %d, got %d", tc.Rounded, tc.Size)
3030
}
3131
}
@@ -63,15 +63,15 @@ func TestConvertToRaw(t *testing.T) {
6363
t.Run("qcow without backing file", func(t *testing.T) {
6464
resultImage := filepath.Join(tmpDir, strings.ReplaceAll(strings.ReplaceAll(t.Name(), string(os.PathSeparator), "_"), "/", "_"))
6565

66-
err = ConvertToRaw(qcowImage.Name(), resultImage, nil, false)
66+
err = convertToRaw(qcowImage.Name(), resultImage, nil, false)
6767
assert.NilError(t, err)
6868
assertFileEquals(t, rawImage.Name(), resultImage)
6969
})
7070

7171
t.Run("qcow with backing file", func(t *testing.T) {
7272
resultImage := filepath.Join(tmpDir, strings.ReplaceAll(strings.ReplaceAll(t.Name(), string(os.PathSeparator), "_"), "/", "_"))
7373

74-
err = ConvertToRaw(qcowImage.Name(), resultImage, nil, true)
74+
err = convertToRaw(qcowImage.Name(), resultImage, nil, true)
7575
assert.NilError(t, err)
7676
assertFileEquals(t, rawImage.Name(), resultImage)
7777
})
@@ -80,15 +80,15 @@ func TestConvertToRaw(t *testing.T) {
8080
resultImage := filepath.Join(tmpDir, strings.ReplaceAll(strings.ReplaceAll(t.Name(), string(os.PathSeparator), "_"), "/", "_"))
8181

8282
size := int64(2_097_152) // 2mb
83-
err = ConvertToRaw(qcowImage.Name(), resultImage, &size, false)
83+
err = convertToRaw(qcowImage.Name(), resultImage, &size, false)
8484
assert.NilError(t, err)
8585
assertFileEquals(t, rawImageExtended.Name(), resultImage)
8686
})
8787

8888
t.Run("raw", func(t *testing.T) {
8989
resultImage := filepath.Join(tmpDir, strings.ReplaceAll(strings.ReplaceAll(t.Name(), string(os.PathSeparator), "_"), "/", "_"))
9090

91-
err = ConvertToRaw(rawImage.Name(), resultImage, nil, false)
91+
err = convertToRaw(rawImage.Name(), resultImage, nil, false)
9292
assert.NilError(t, err)
9393
assertFileEquals(t, rawImage.Name(), resultImage)
9494
})
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
// SPDX-FileCopyrightText: Copyright The Lima Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package proxyimgutil
5+
6+
import (
7+
"errors"
8+
"os"
9+
"os/exec"
10+
11+
"github.com/lima-vm/lima/pkg/imgutil"
12+
"github.com/lima-vm/lima/pkg/imgutil/nativeimgutil"
13+
"github.com/lima-vm/lima/pkg/imgutil/qemuimgutil"
14+
)
15+
16+
// ImageDiskManager is a proxy implementation of imgutil.ImageDiskManager that uses both QEMU and native image utilities.
17+
type ImageDiskManager struct {
18+
qemu imgutil.ImageDiskManager
19+
native imgutil.ImageDiskManager
20+
}
21+
22+
// NewDiskUtil returns a new instance of ImageDiskManager that uses both QEMU and native image utilities.
23+
func NewDiskUtil() imgutil.ImageDiskManager {
24+
return &ImageDiskManager{
25+
qemu: &qemuimgutil.QemuImageUtil{DefaultFormat: qemuimgutil.QEMUIMGFORMAT},
26+
native: &nativeimgutil.NativeImageUtil{},
27+
}
28+
}
29+
30+
// CreateDisk creates a new disk image with the specified size.
31+
func (p *ImageDiskManager) CreateDisk(disk string, size int64) error {
32+
err := p.qemu.CreateDisk(disk, size)
33+
if err == nil {
34+
return nil
35+
}
36+
if errors.Is(err, exec.ErrNotFound) {
37+
return p.native.CreateDisk(disk, size)
38+
}
39+
return err
40+
}
41+
42+
// ResizeDisk resizes an existing disk image to the specified size.
43+
func (p *ImageDiskManager) ResizeDisk(disk string, size int64) error {
44+
err := p.qemu.ResizeDisk(disk, size)
45+
if err == nil {
46+
return nil
47+
}
48+
if errors.Is(err, exec.ErrNotFound) {
49+
return p.native.ResizeDisk(disk, size)
50+
}
51+
return err
52+
}
53+
54+
// ConvertToRaw converts a disk image to raw format.
55+
func (p *ImageDiskManager) ConvertToRaw(source, dest string, size *int64, allowSourceWithBackingFile bool) error {
56+
err := p.qemu.ConvertToRaw(source, dest, size, allowSourceWithBackingFile)
57+
if err == nil {
58+
return nil
59+
}
60+
if errors.Is(err, exec.ErrNotFound) {
61+
return p.native.ConvertToRaw(source, dest, size, allowSourceWithBackingFile)
62+
}
63+
return err
64+
}
65+
66+
func (p *ImageDiskManager) MakeSparse(f *os.File, offset int64) error {
67+
err := p.qemu.MakeSparse(f, offset)
68+
if err == nil {
69+
return nil
70+
}
71+
if errors.Is(err, exec.ErrNotFound) {
72+
return p.native.MakeSparse(f, offset)
73+
}
74+
return err
75+
}

0 commit comments

Comments
 (0)