mirror of
https://github.com/lima-vm/lima.git
synced 2026-10-28 11:44:35 +08:00
127 lines
4.3 KiB
Go
127 lines
4.3 KiB
Go
// SPDX-FileCopyrightText: Copyright The Lima Authors
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package driverutil
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
"github.com/docker/go-units"
|
|
"github.com/lima-vm/go-qcow2reader/image"
|
|
"github.com/lima-vm/go-qcow2reader/image/vhdx"
|
|
"github.com/sirupsen/logrus"
|
|
|
|
"github.com/lima-vm/lima/v2/pkg/imgutil/nativeimgutil"
|
|
"github.com/lima-vm/lima/v2/pkg/imgutil/proxyimgutil"
|
|
"github.com/lima-vm/lima/v2/pkg/iso9660util"
|
|
"github.com/lima-vm/lima/v2/pkg/limatype/filenames"
|
|
"github.com/lima-vm/lima/v2/pkg/osutil"
|
|
)
|
|
|
|
// MigrateDiskLayout creates symlinks from the current filenames (disk, iso) to
|
|
// the legacy filenames (diffdisk, basedisk) used by older Lima versions.
|
|
// The original files are left in place so older Lima versions can still use them.
|
|
func MigrateDiskLayout(instDir string) error {
|
|
diskPath := filepath.Join(instDir, filenames.Disk)
|
|
if osutil.FileExists(diskPath) {
|
|
return nil // already migrated or new instance
|
|
}
|
|
|
|
diffDiskPath := filepath.Join(instDir, filenames.DiffDiskLegacy)
|
|
if osutil.FileExists(diffDiskPath) {
|
|
logrus.Infof("Creating symlink %#q -> %#q", filenames.Disk, filenames.DiffDiskLegacy)
|
|
if err := os.Symlink(filenames.DiffDiskLegacy, diskPath); err != nil {
|
|
return fmt.Errorf("failed to symlink %#q to %#q: %w", filenames.Disk, filenames.DiffDiskLegacy, err)
|
|
}
|
|
}
|
|
|
|
baseDiskPath := filepath.Join(instDir, filenames.BaseDiskLegacy)
|
|
isoPath := filepath.Join(instDir, filenames.ISO)
|
|
if osutil.FileExists(baseDiskPath) && !osutil.FileExists(isoPath) {
|
|
isISO, err := iso9660util.IsISO9660(baseDiskPath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if isISO {
|
|
logrus.Infof("Creating symlink %#q -> %#q", filenames.ISO, filenames.BaseDiskLegacy)
|
|
if err := os.Symlink(filenames.BaseDiskLegacy, isoPath); err != nil {
|
|
return fmt.Errorf("failed to symlink %#q to %#q: %w", filenames.ISO, filenames.BaseDiskLegacy, err)
|
|
}
|
|
}
|
|
// Non-ISO basedisk is a legacy qcow2 backing file; leave it for QEMU to resolve.
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// EnsureDisk creates the VM disk from the downloaded image.
|
|
// For ISO images, it renames the image to "iso" and creates an empty disk.
|
|
// For non-ISO images, it converts the image to "disk" and removes the original.
|
|
func EnsureDisk(ctx context.Context, instDir, diskSize string, diskImageFormat image.Type) error {
|
|
diskPath := filepath.Join(instDir, filenames.Disk)
|
|
if _, err := os.Stat(diskPath); err == nil || !errors.Is(err, os.ErrNotExist) {
|
|
return err
|
|
}
|
|
|
|
imagePath := filepath.Join(instDir, filenames.Image)
|
|
isISO, err := iso9660util.IsISO9660(imagePath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
diskSizeInBytes, _ := units.RAMInBytes(diskSize)
|
|
diskUtil := proxyimgutil.NewDiskUtil(ctx)
|
|
|
|
if isISO {
|
|
isoPath := filepath.Join(instDir, filenames.ISO)
|
|
if err := os.Rename(imagePath, isoPath); err != nil {
|
|
return err
|
|
}
|
|
f, err := os.Create(diskPath)
|
|
if err != nil {
|
|
_ = os.Rename(isoPath, imagePath)
|
|
return err
|
|
}
|
|
if err := f.Close(); err != nil {
|
|
os.Remove(diskPath)
|
|
_ = os.Rename(isoPath, imagePath)
|
|
return err
|
|
}
|
|
if err := diskUtil.Convert(ctx, diskImageFormat, diskPath, diskPath, &diskSizeInBytes, false); err != nil {
|
|
os.Remove(diskPath)
|
|
_ = os.Rename(isoPath, imagePath)
|
|
return fmt.Errorf("failed to create disk %#q: %w", diskPath, err)
|
|
}
|
|
} else {
|
|
format, err := nativeimgutil.DetectFormat(imagePath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Resize handled by prepareDisk() after CreateDisk(), except for a format
|
|
// whose size go-qcow2reader cannot read: prepareDisk() skips it, so the
|
|
// image keeps its own virtual size instead of diskSize.
|
|
if format == string(diskImageFormat) {
|
|
if diskImageFormat == vhdx.Type {
|
|
logrus.Warnf("Disk size %#q is not applied to %#q: a %s image keeps the virtual size it was built with", diskSize, diskPath, diskImageFormat)
|
|
}
|
|
if err = os.Rename(imagePath, diskPath); err != nil {
|
|
return fmt.Errorf("failed to rename %#q to %#q: %w", imagePath, diskPath, err)
|
|
}
|
|
if err := os.Chmod(diskPath, 0o644); err != nil {
|
|
return fmt.Errorf("failed to chmod %#q: %w", diskPath, err)
|
|
}
|
|
} else {
|
|
if err := diskUtil.Convert(ctx, diskImageFormat, imagePath, diskPath, &diskSizeInBytes, false); err != nil {
|
|
return fmt.Errorf("failed to convert %#q to %#q: %w", imagePath, diskPath, err)
|
|
}
|
|
os.Remove(imagePath)
|
|
}
|
|
}
|
|
return nil
|
|
}
|