Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

vm: support additional disks #893

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -442,7 +442,10 @@ func generateSSHConfig(modifySSHConfig bool) error {
continue
}

fmt.Fprintln(&buf, resp.Output)
_, err = fmt.Fprintln(&buf, resp.Output)
if err != nil {
return err
}
}

sshFileColima := config.SSHConfigFile()
Expand Down
4 changes: 3 additions & 1 deletion cli/chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package cli

import (
"context"
"errors"
"fmt"
"io"
"time"
Expand Down Expand Up @@ -118,7 +119,8 @@ func (a ActiveCommandChain) Exec() error {
}

// warning
if _, ok := err.(errNonFatal); ok {
var errNonFatal errNonFatal
if errors.As(err, &errNonFatal) {
if a.lastStage == "" {
a.log.Warnln(err)
} else {
Expand Down
2 changes: 1 addition & 1 deletion cmd/clone.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ var cloneCmd = &cobra.Command{
}

configFile := func(p config.ProfileInfo) string {
return filepath.Join(filepath.Dir(config.Dir()), p.ShortName, config.ConfigFileName)
return filepath.Join(filepath.Dir(config.Dir()), p.ShortName, config.FileName)
}

logrus.Infof("preparing to clone %s...", from.DisplayName)
Expand Down
2 changes: 1 addition & 1 deletion cmd/daemon/daemon.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ func Info() struct {
}
}

// Run runs the daemon with background processes.
// RunProcesses Run runs the daemon with background processes.
// NOTE: this must be called from the program entrypoint with minimal intermediary logic
// due to the creation of the daemon.
func RunProcesses(ctx context.Context, processes ...process.Process) error {
Expand Down
3 changes: 2 additions & 1 deletion cmd/daemon/daemon_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package daemon

import (
"context"
"errors"
"os"
"os/exec"
"testing"
Expand Down Expand Up @@ -103,7 +104,7 @@ func TestRunProcesses(t *testing.T) {

select {
case <-ctx.Done():
if err := ctx.Err(); err != context.Canceled {
if err := ctx.Err(); !errors.Is(err, context.Canceled) {
t.Error(err)
}
case err := <-done:
Expand Down
2 changes: 1 addition & 1 deletion cmd/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ var listCmd = &cobra.Command{
A new instance can be created during 'colima start' by specifying the '--profile' flag.`,
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
profile := []string{}
var profile []string
if cmd.Flag("profile").Changed {
profile = append(profile, config.CurrentProfile().ID)
}
Expand Down
6 changes: 6 additions & 0 deletions cmd/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,9 @@ func init() {
startCmd.Flags().StringVar(&startCmdArgs.MountType, "mount-type", defaultMountTypeQEMU, "volume driver for the mount ("+mounts+")")
startCmd.Flags().BoolVar(&startCmdArgs.MountINotify, "mount-inotify", true, "propagate inotify file events to the VM")

// lima disks
startCmd.Flags().StringSliceVarP(&startCmdArgs.Flags.Mounts, "lima-disk", "D", nil, "map of disk name and size e.g. --lima-disk=my-disk,10G")

// ssh agent
startCmd.Flags().BoolVarP(&startCmdArgs.ForwardAgent, "ssh-agent", "s", false, "forward SSH agent to the VM")

Expand Down Expand Up @@ -372,6 +375,9 @@ func prepareConfig(cmd *cobra.Command) {
if !cmd.Flag("mount-inotify").Changed {
startCmdArgs.MountINotify = current.MountINotify
}
if !cmd.Flag("lima-disk").Changed {
startCmdArgs.LimaDisks = current.LimaDisks
}
if !cmd.Flag("ssh-agent").Changed {
startCmdArgs.ForwardAgent = current.ForwardAgent
}
Expand Down
12 changes: 12 additions & 0 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@ type Config struct {
VMType string `yaml:"vmType,omitempty"`
VZRosetta bool `yaml:"rosetta,omitempty"`

// disks
LimaDisks []Disk `yaml:"limaDisks,omitempty"`

// volume mounts
Mounts []Mount `yaml:"mounts,omitempty"`
MountType string `yaml:"mountType,omitempty"`
Expand All @@ -105,6 +108,15 @@ type Config struct {
SSHConfig bool `yaml:"sshConfig,omitempty"`
}

type Disk struct {
Name string `yaml:"name"`
Size string `yaml:"size"`
ImageFormat string `yaml:"imageFormat,omitempty" json:"imageFormat,omitempty"`
Format bool `yaml:"format,omitempty" json:"format,omitempty"`
FSType string `yaml:"fsType,omitempty" json:"fsType,omitempty"`
FSArgs []string `yaml:"fsArgs,omitempty" json:"fsArgs,omitempty"`
}

// Kubernetes is kubernetes configuration
type Kubernetes struct {
Enabled bool `yaml:"enabled"`
Expand Down
2 changes: 1 addition & 1 deletion config/configmanager/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,6 @@ func ValidateConfig(c config.Config) error {
if _, ok := validVMTypes[c.VMType]; !ok {
return fmt.Errorf("invalid vmType: '%s'", c.VMType)
}

return nil
}

Expand All @@ -85,6 +84,7 @@ func Load() (config.Config, error) {

// config file does not exist, check older version for backward compatibility
if _, err := os.Stat(oldCFile); err != nil {
logrus.Warn(fmt.Errorf("error loading config: %w, proceeding with defaults", err))
return config.Config{}, nil
}

Expand Down
6 changes: 3 additions & 3 deletions config/dirs.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,12 +123,12 @@ func CacheDir() string { return cacheDir.Dir() }
// TemplatesDir returns the templates' directory.
func TemplatesDir() string { return templatesDir.Dir() }

// TemplatesDir returns the templates' directory.
// LimaDir returns the lima directory.
func LimaDir() string { return limaDir.Dir() }

const ConfigFileName = "colima.yaml"
const FileName = "colima.yaml"

func configFile() string { return filepath.Join(configDir.Dir(), ConfigFileName) }
func configFile() string { return filepath.Join(configDir.Dir(), FileName) }

// SSHConfigFile returns the path to generated ssh config.
func SSHConfigFile() string { return filepath.Join(filepath.Dir(configDir.Dir()), "ssh_config") }
4 changes: 2 additions & 2 deletions core/core.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,13 +131,13 @@ func LimaVersionSupported() error {
return nil
}

min := semver.New(strings.TrimPrefix(limaVersion, "v"))
minimum := semver.New(strings.TrimPrefix(limaVersion, "v"))
current, err := semver.NewVersion(strings.TrimPrefix(values.Version, "v"))
if err != nil {
return fmt.Errorf("invalid semver version for Lima: %w", err)
}

if min.Compare(*current) > 0 {
if minimum.Compare(*current) > 0 {
return fmt.Errorf("minimum Lima version supported is %s, current version is %s", limaVersion, values.Version)
}

Expand Down
2 changes: 1 addition & 1 deletion daemon/process/inotify/volumes.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ func (f *inotifyProcess) monitorContainerVolumes(ctx context.Context, c chan<- [
}

// process and discard redundant volumes
vols := []string{}
var vols []string
{
shouldMount := func(child string) bool {
// ignore all invalid directories.
Expand Down
14 changes: 14 additions & 0 deletions embedded/defaults/colima.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,20 @@ sshConfig: true
# Default: []
mounts: []

# Configure additional disks
#
# EXAMPLE
# disks:
# - name: mydisk
# size: 20G
# imageFormat: raw (optional) qemu-img image format
# format: false (optional) whether to format the disk
# fsType: ext4 (optional) filesystem type
# fsArgs: [] (optional) qemu-img arguments
# - name: otherdisk
# size: 1M
limaDisks: []

# Environment variables for the virtual machine.
#
# EXAMPLE
Expand Down
2 changes: 1 addition & 1 deletion embedded/embed.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
var fs embed.FS

// FS returns the underlying embed.FS
func FS() embed.FS { return fs }
// func FS() embed.FS { return fs }

func read(file string) ([]byte, error) { return fs.ReadFile(file) }

Expand Down
2 changes: 1 addition & 1 deletion environment/container/docker/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ var (
noProxy proxyVarKey = "no_proxy"
)

// keys return both the lower case and upper case env var keys.
// Keys return both the lower case and upper case env var keys.
// e.g. http_proxy and HTTP_PROXY
func (p proxyVarKey) Keys() []string {
return []string{string(p), strings.ToUpper(string(p))}
Expand Down
122 changes: 122 additions & 0 deletions environment/vm/lima/disk.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
package lima

import (
"encoding/json"
"fmt"
"github.com/abiosoft/colima/config"
"github.com/docker/go-units"
"github.com/sirupsen/logrus"
"strconv"
"strings"
)

func (l *limaVM) updateLimaDisks(conf config.Config) ([]DiskListOutput, error) {
logrus.Trace(fmt.Errorf("updating lima disks"))
out, err := l.host.RunOutput(limactl, "disk", "list", "--json")
if err != nil {
logrus.Trace(fmt.Errorf("error listing disks: %s, %s", out, err))
return []DiskListOutput{}, err
}
logrus.Trace(fmt.Errorf("listing disks: %s", out))

var listedDisks []DiskListOutput
if out != "" {
for _, line := range strings.Split(strings.TrimSuffix(out, "\n"), "\n") {
var listedDisk DiskListOutput
err = json.Unmarshal([]byte(line), &listedDisk)
if err != nil {
logrus.Trace(fmt.Errorf("error unmarshaling listed disks: %s", err))
return []DiskListOutput{}, err
}
listedDisks = append(listedDisks, listedDisk)
}
}

var disksToCreate []config.Disk
for _, disk := range conf.LimaDisks {
diskName := config.CurrentProfile().ID + "-" + disk.Name
var found = false
for _, listedDisk := range listedDisks {
if listedDisk.Name == diskName {
found = true
break
}
}
if !found {
disksToCreate = append(disksToCreate, disk)
}
}

for _, disk := range disksToCreate {
diskName := config.CurrentProfile().ID + "-" + disk.Name
logrus.Trace(fmt.Errorf("creating disk %s", diskName))
diskFormat := "--format=raw"
if disk.FSType != "" {
diskFormat = "--format=" + disk.FSType
}
out, err = l.host.RunOutput(limactl, "disk", "create", diskName, "--size", disk.Size, diskFormat)
if err != nil {
logrus.Trace(fmt.Errorf("error creating disk: %s, %s", out, err))
return []DiskListOutput{}, err
}
logrus.Trace(fmt.Errorf("disk create output: %s", out))
}

var disksToDelete []DiskListOutput
for _, listedDisk := range listedDisks {
var found = false
for _, disk := range conf.LimaDisks {
diskName := config.CurrentProfile().ID + "-" + disk.Name
if listedDisk.Name == diskName {
found = true
diskSize, err := units.RAMInBytes(disk.Size)
if err != nil {
logrus.Trace(fmt.Errorf("error parsing disk size: %s", err))
return []DiskListOutput{}, err
}
logrus.Trace(fmt.Errorf("disk size: %d", diskSize))
switch disk.FSType {
case "raw":
if diskSize != listedDisk.Size {
l.resizeLimaDisk(diskName, diskSize)
}
case "qcow2":
if diskSize != 0 {
return []DiskListOutput{}, fmt.Errorf("%s cannot be updated: limactl does not support updating disks", diskName)
}
}
logrus.Trace(fmt.Errorf("disk %s is up to date", diskName))
continue

}
}
if !found {
disksToDelete = append(disksToDelete, listedDisk)
}
}

for _, disk := range disksToDelete {
l.deleteLimaDisk(disk.Name)
}

return disksToDelete, nil
}

func (l *limaVM) resizeLimaDisk(diskName string, diskSize int64) {
out, err := l.host.RunOutput(limactl, "disk", "resize", diskName, "--size", strconv.FormatInt(diskSize, 10))
if err != nil {
logrus.Trace(fmt.Errorf("error resizing disk: %s, %s", out, err))
return
}
logrus.Trace(fmt.Errorf("disk resize output: %s", out))
}

func (l *limaVM) deleteLimaDisk(diskName string) {
logrus.Trace(fmt.Errorf("deleting disk %s", diskName))
out, err := l.host.RunOutput(limactl, "disk", "delete", "--force", diskName)
if err != nil {
logrus.Trace(fmt.Errorf("error deleting disk: %s, %s", out, err))
return
}
logrus.Trace(fmt.Errorf("disk delete output: %s", out))
}
Loading