Skip to content

Commit 7e1160d

Browse files
committed
limayaml: add a .suspendOnSigInt field to control whether to use suspend
default `false` Signed-off-by: Norio Nomura <[email protected]>
1 parent 9dcdcac commit 7e1160d

File tree

6 files changed

+50
-5
lines changed

6 files changed

+50
-5
lines changed

pkg/limayaml/defaults.go

+27
Original file line numberDiff line numberDiff line change
@@ -855,6 +855,32 @@ func FillDefault(y, d, o *LimaYAML, filePath string, warn bool) {
855855
y.NestedVirtualization = ptr.Of(false)
856856
}
857857

858+
if y.SuspendOnSigInt == nil {
859+
y.SuspendOnSigInt = d.SuspendOnSigInt
860+
}
861+
if o.SuspendOnSigInt != nil {
862+
y.SuspendOnSigInt = o.SuspendOnSigInt
863+
}
864+
if y.SuspendOnSigInt == nil {
865+
y.SuspendOnSigInt = ptr.Of(false)
866+
}
867+
if *y.SuspendOnSigInt {
868+
y.SuspendOnSigInt = ptr.Of(false)
869+
if *y.VMType != VZ {
870+
logrus.Warn("suspend is only supported for VM type vz")
871+
} else if runtime.GOARCH != "arm64" {
872+
logrus.Warn("suspend is only supported for arm64 VM type vz")
873+
} else if runtime.GOOS != "darwin" {
874+
logrus.Warn("suspend is only supported on macOS")
875+
} else if macOSProductVersion, err := osutil.ProductVersion(); err != nil {
876+
logrus.WithError(err).Warn("Failed to get macOS product version")
877+
} else if macOSProductVersion.LessThan(*semver.New("14.0.0")) {
878+
logrus.Warn("suspend is not supported on macOS prior to 14.0")
879+
} else {
880+
y.SuspendOnSigInt = ptr.Of(true)
881+
}
882+
}
883+
858884
if y.Plain == nil {
859885
y.Plain = d.Plain
860886
}
@@ -878,6 +904,7 @@ func fixUpForPlainMode(y *LimaYAML) {
878904
y.Containerd.User = ptr.Of(false)
879905
y.Rosetta.BinFmt = ptr.Of(false)
880906
y.Rosetta.Enabled = ptr.Of(false)
907+
y.SuspendOnSigInt = ptr.Of(false)
881908
y.TimeZone = ptr.Of("")
882909
}
883910

pkg/limayaml/defaults_test.go

+6
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ func TestFillDefault(t *testing.T) {
112112
RemoveDefaults: ptr.Of(false),
113113
},
114114
NestedVirtualization: ptr.Of(false),
115+
SuspendOnSigInt: ptr.Of(false),
115116
Plain: ptr.Of(false),
116117
User: User{
117118
Name: ptr.Of(user.Username),
@@ -437,6 +438,7 @@ func TestFillDefault(t *testing.T) {
437438
BinFmt: ptr.Of(true),
438439
},
439440
NestedVirtualization: ptr.Of(true),
441+
SuspendOnSigInt: ptr.Of(true),
440442
User: User{
441443
Name: ptr.Of("xxx"),
442444
Comment: ptr.Of("Foo Bar"),
@@ -474,11 +476,13 @@ func TestFillDefault(t *testing.T) {
474476
Enabled: ptr.Of(true),
475477
BinFmt: ptr.Of(true),
476478
}
479+
expect.SuspendOnSigInt = ptr.Of(true)
477480
} else {
478481
expect.Rosetta = Rosetta{
479482
Enabled: ptr.Of(false),
480483
BinFmt: ptr.Of(true),
481484
}
485+
expect.SuspendOnSigInt = ptr.Of(false)
482486
}
483487
expect.Plain = ptr.Of(false)
484488

@@ -660,6 +664,7 @@ func TestFillDefault(t *testing.T) {
660664
BinFmt: ptr.Of(false),
661665
},
662666
NestedVirtualization: ptr.Of(false),
667+
SuspendOnSigInt: ptr.Of(false),
663668
User: User{
664669
Name: ptr.Of("foo"),
665670
Comment: ptr.Of("foo bar baz"),
@@ -723,6 +728,7 @@ func TestFillDefault(t *testing.T) {
723728
expect.Plain = ptr.Of(false)
724729

725730
expect.NestedVirtualization = ptr.Of(false)
731+
expect.SuspendOnSigInt = ptr.Of(false)
726732

727733
FillDefault(&y, &d, &o, filePath, false)
728734
assert.DeepEqual(t, &y, &expect, opts...)

pkg/limayaml/limayaml.go

+1
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ type LimaYAML struct {
4848
TimeZone *string `yaml:"timezone,omitempty" json:"timezone,omitempty" jsonschema:"nullable"`
4949
NestedVirtualization *bool `yaml:"nestedVirtualization,omitempty" json:"nestedVirtualization,omitempty" jsonschema:"nullable"`
5050
User User `yaml:"user,omitempty" json:"user,omitempty"`
51+
SuspendOnSigInt *bool `yaml:"suspendOnSigInt,omitempty" json:"suspend,omitempty" jsonschema:"nullable"`
5152
}
5253

5354
type (

pkg/store/instance.go

+3
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ type Instance struct {
6363
Protected bool `json:"protected"`
6464
LimaVersion string `json:"limaVersion"`
6565
Param map[string]string `json:"param,omitempty"`
66+
SuspendOnSigInt bool `json:"suspendOnSigInt"`
6667
}
6768

6869
// Inspect returns err only when the instance does not exist (os.ErrNotExist).
@@ -179,6 +180,8 @@ func Inspect(instName string) (*Instance, error) {
179180
inst.Errors = append(inst.Errors, err)
180181
}
181182
inst.Param = y.Param
183+
// It might be changed by request from other limactl processes. So, copy it from the config.
184+
inst.SuspendOnSigInt = *y.SuspendOnSigInt
182185
return inst, nil
183186
}
184187

pkg/vz/vz_driver_darwin.go

+8-5
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ var knownYamlProperties = []string{
5353
"PropagateProxyEnv",
5454
"Provision",
5555
"Rosetta",
56+
"SuspendOnSigInt",
5657
"SSH",
5758
"TimeZone",
5859
"UpgradePackages",
@@ -193,11 +194,13 @@ func (l *LimaVzDriver) RunGUI() error {
193194
}
194195

195196
func (l *LimaVzDriver) Stop(_ context.Context) error {
196-
machineStatePath := filepath.Join(l.Instance.Dir, filenames.VzMachineState)
197-
if err := suspendVM(l.machine.VirtualMachine, machineStatePath); err != nil {
198-
logrus.WithError(err).Warn("Failed to suspend VZ. Falling back to shutdown")
199-
} else {
200-
return nil
197+
if l.Instance.SuspendOnSigInt {
198+
machineStatePath := filepath.Join(l.Instance.Dir, filenames.VzMachineState)
199+
if err := suspendVM(l.machine.VirtualMachine, machineStatePath); err != nil {
200+
logrus.WithError(err).Warn("Failed to suspend VZ. Falling back to shutdown")
201+
} else {
202+
return nil
203+
}
201204
}
202205

203206
logrus.Info("Shutting down VZ")

templates/default.yaml

+5
Original file line numberDiff line numberDiff line change
@@ -525,6 +525,11 @@ hostResolver:
525525
# 🟢 Builtin default: /usr/local
526526
guestInstallPrefix: null
527527

528+
# When "suspendOnSigInt" is enabled, Lima suspends the VM instead of shutting it down.
529+
# The VM can be resumed with `limactl start` if the saved state is available.
530+
# 🟢 Builtin default: false
531+
suspendOnSigInt: null
532+
528533
# When the "plain" mode is enabled:
529534
# - the YAML properties for mounts, port forwarding, containerd, etc. will be ignored
530535
# - guest agent will not be running

0 commit comments

Comments
 (0)