Skip to content

Commit e0edc70

Browse files
authored
Merge pull request #2504 from rancher-sandbox/refactor-stop-delete
Refactor stop/delete logic into pkg/instance
2 parents 3a6c1a6 + 9632b89 commit e0edc70

File tree

6 files changed

+166
-159
lines changed

6 files changed

+166
-159
lines changed

cmd/limactl/delete.go

+2-24
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
11
package main
22

33
import (
4-
"context"
54
"errors"
65
"fmt"
76
"os"
87
"runtime"
98

109
"github.com/lima-vm/lima/pkg/autostart"
10+
"github.com/lima-vm/lima/pkg/instance"
1111
networks "github.com/lima-vm/lima/pkg/networks/reconcile"
12-
"github.com/lima-vm/lima/pkg/stop"
1312
"github.com/lima-vm/lima/pkg/store"
1413
"github.com/sirupsen/logrus"
1514
"github.com/spf13/cobra"
@@ -43,7 +42,7 @@ func deleteAction(cmd *cobra.Command, args []string) error {
4342
}
4443
return err
4544
}
46-
if err := deleteInstance(cmd.Context(), inst, force); err != nil {
45+
if err := instance.Delete(cmd.Context(), inst, force); err != nil {
4746
return fmt.Errorf("failed to delete instance %q: %w", instName, err)
4847
}
4948
if runtime.GOOS == "darwin" || runtime.GOOS == "linux" {
@@ -59,27 +58,6 @@ func deleteAction(cmd *cobra.Command, args []string) error {
5958
return networks.Reconcile(cmd.Context(), "")
6059
}
6160

62-
func deleteInstance(ctx context.Context, inst *store.Instance, force bool) error {
63-
if inst.Protected {
64-
return fmt.Errorf("instance is protected to prohibit accidental removal (Hint: use `limactl unprotect`)")
65-
}
66-
if !force && inst.Status != store.StatusStopped {
67-
return fmt.Errorf("expected status %q, got %q", store.StatusStopped, inst.Status)
68-
}
69-
70-
stopInstanceForcibly(inst)
71-
72-
if err := stop.Unregister(ctx, inst); err != nil {
73-
return fmt.Errorf("failed to unregister %q: %w", inst.Dir, err)
74-
}
75-
76-
if err := os.RemoveAll(inst.Dir); err != nil {
77-
return fmt.Errorf("failed to remove %q: %w", inst.Dir, err)
78-
}
79-
80-
return nil
81-
}
82-
8361
func deleteBashComplete(cmd *cobra.Command, _ []string, _ string) ([]string, cobra.ShellCompDirective) {
8462
return bashCompleteInstanceNames(cmd)
8563
}

cmd/limactl/factory-reset.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"path/filepath"
77
"strings"
88

9+
"github.com/lima-vm/lima/pkg/instance"
910
"github.com/lima-vm/lima/pkg/store"
1011
"github.com/lima-vm/lima/pkg/store/filenames"
1112
"github.com/sirupsen/logrus"
@@ -39,7 +40,7 @@ func factoryResetAction(_ *cobra.Command, args []string) error {
3940
return err
4041
}
4142

42-
stopInstanceForcibly(inst)
43+
instance.StopForcibly(inst)
4344

4445
fi, err := os.ReadDir(inst.Dir)
4546
if err != nil {

cmd/limactl/stop.go

+3-110
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,9 @@
11
package main
22

33
import (
4-
"context"
5-
"errors"
6-
"fmt"
7-
"os"
8-
"path/filepath"
9-
"strings"
10-
"time"
11-
12-
hostagentevents "github.com/lima-vm/lima/pkg/hostagent/events"
4+
"github.com/lima-vm/lima/pkg/instance"
135
networks "github.com/lima-vm/lima/pkg/networks/reconcile"
14-
"github.com/lima-vm/lima/pkg/osutil"
156
"github.com/lima-vm/lima/pkg/store"
16-
"github.com/lima-vm/lima/pkg/store/filenames"
17-
"github.com/sirupsen/logrus"
187
"github.com/spf13/cobra"
198
)
209

@@ -48,9 +37,9 @@ func stopAction(cmd *cobra.Command, args []string) error {
4837
return err
4938
}
5039
if force {
51-
stopInstanceForcibly(inst)
40+
instance.StopForcibly(inst)
5241
} else {
53-
err = stopInstanceGracefully(inst)
42+
err = instance.StopGracefully(inst)
5443
}
5544
// TODO: should we also reconcile networks if graceful stop returned an error?
5645
if err == nil {
@@ -59,102 +48,6 @@ func stopAction(cmd *cobra.Command, args []string) error {
5948
return err
6049
}
6150

62-
func stopInstanceGracefully(inst *store.Instance) error {
63-
if inst.Status != store.StatusRunning {
64-
return fmt.Errorf("expected status %q, got %q (maybe use `limactl stop -f`?)", store.StatusRunning, inst.Status)
65-
}
66-
67-
begin := time.Now() // used for logrus propagation
68-
logrus.Infof("Sending SIGINT to hostagent process %d", inst.HostAgentPID)
69-
if err := osutil.SysKill(inst.HostAgentPID, osutil.SigInt); err != nil {
70-
logrus.Error(err)
71-
}
72-
73-
logrus.Info("Waiting for the host agent and the driver processes to shut down")
74-
return waitForHostAgentTermination(context.TODO(), inst, begin)
75-
}
76-
77-
func waitForHostAgentTermination(ctx context.Context, inst *store.Instance, begin time.Time) error {
78-
ctx2, cancel := context.WithTimeout(ctx, 3*time.Minute+10*time.Second)
79-
defer cancel()
80-
81-
var receivedExitingEvent bool
82-
onEvent := func(ev hostagentevents.Event) bool {
83-
if len(ev.Status.Errors) > 0 {
84-
logrus.Errorf("%+v", ev.Status.Errors)
85-
}
86-
if ev.Status.Exiting {
87-
receivedExitingEvent = true
88-
return true
89-
}
90-
return false
91-
}
92-
93-
haStdoutPath := filepath.Join(inst.Dir, filenames.HostAgentStdoutLog)
94-
haStderrPath := filepath.Join(inst.Dir, filenames.HostAgentStderrLog)
95-
96-
if err := hostagentevents.Watch(ctx2, haStdoutPath, haStderrPath, begin, onEvent); err != nil {
97-
return err
98-
}
99-
100-
if !receivedExitingEvent {
101-
return errors.New("did not receive an event with the \"exiting\" status")
102-
}
103-
104-
return nil
105-
}
106-
107-
func stopInstanceForcibly(inst *store.Instance) {
108-
if inst.DriverPID > 0 {
109-
logrus.Infof("Sending SIGKILL to the %s driver process %d", inst.VMType, inst.DriverPID)
110-
if err := osutil.SysKill(inst.DriverPID, osutil.SigKill); err != nil {
111-
logrus.Error(err)
112-
}
113-
} else {
114-
logrus.Infof("The %s driver process seems already stopped", inst.VMType)
115-
}
116-
117-
for _, d := range inst.AdditionalDisks {
118-
diskName := d.Name
119-
disk, err := store.InspectDisk(diskName)
120-
if err != nil {
121-
logrus.Warnf("Disk %q does not exist", diskName)
122-
continue
123-
}
124-
if err := disk.Unlock(); err != nil {
125-
logrus.Warnf("Failed to unlock disk %q. To use, run `limactl disk unlock %v`", diskName, diskName)
126-
}
127-
}
128-
129-
if inst.HostAgentPID > 0 {
130-
logrus.Infof("Sending SIGKILL to the host agent process %d", inst.HostAgentPID)
131-
if err := osutil.SysKill(inst.HostAgentPID, osutil.SigKill); err != nil {
132-
logrus.Error(err)
133-
}
134-
} else {
135-
logrus.Info("The host agent process seems already stopped")
136-
}
137-
138-
suffixesToBeRemoved := []string{".pid", ".sock", ".tmp"}
139-
logrus.Infof("Removing %s under %q", inst.Dir, strings.ReplaceAll(strings.Join(suffixesToBeRemoved, " "), ".", "*."))
140-
fi, err := os.ReadDir(inst.Dir)
141-
if err != nil {
142-
logrus.Error(err)
143-
return
144-
}
145-
for _, f := range fi {
146-
path := filepath.Join(inst.Dir, f.Name())
147-
for _, suffix := range suffixesToBeRemoved {
148-
if strings.HasSuffix(path, suffix) {
149-
logrus.Infof("Removing %q", path)
150-
if err := os.Remove(path); err != nil {
151-
logrus.Error(err)
152-
}
153-
}
154-
}
155-
}
156-
}
157-
15851
func stopBashComplete(cmd *cobra.Command, _ []string, _ string) ([]string, cobra.ShellCompDirective) {
15952
return bashCompleteInstanceNames(cmd)
16053
}

pkg/instance/delete.go

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package instance
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"os"
7+
8+
"github.com/lima-vm/lima/pkg/driver"
9+
"github.com/lima-vm/lima/pkg/driverutil"
10+
"github.com/lima-vm/lima/pkg/store"
11+
)
12+
13+
func Delete(ctx context.Context, inst *store.Instance, force bool) error {
14+
if inst.Protected {
15+
return fmt.Errorf("instance is protected to prohibit accidental removal (Hint: use `limactl unprotect`)")
16+
}
17+
if !force && inst.Status != store.StatusStopped {
18+
return fmt.Errorf("expected status %q, got %q", store.StatusStopped, inst.Status)
19+
}
20+
21+
StopForcibly(inst)
22+
23+
if err := unregister(ctx, inst); err != nil {
24+
return fmt.Errorf("failed to unregister %q: %w", inst.Dir, err)
25+
}
26+
27+
if err := os.RemoveAll(inst.Dir); err != nil {
28+
return fmt.Errorf("failed to remove %q: %w", inst.Dir, err)
29+
}
30+
31+
return nil
32+
}
33+
34+
func unregister(ctx context.Context, inst *store.Instance) error {
35+
y, err := inst.LoadYAML()
36+
if err != nil {
37+
return err
38+
}
39+
40+
limaDriver := driverutil.CreateTargetDriverInstance(&driver.BaseDriver{
41+
Instance: inst,
42+
Yaml: y,
43+
})
44+
45+
return limaDriver.Unregister(ctx)
46+
}

pkg/instance/stop.go

+113
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
package instance
2+
3+
import (
4+
"context"
5+
"errors"
6+
"fmt"
7+
"os"
8+
"path/filepath"
9+
"strings"
10+
"time"
11+
12+
hostagentevents "github.com/lima-vm/lima/pkg/hostagent/events"
13+
"github.com/lima-vm/lima/pkg/osutil"
14+
"github.com/lima-vm/lima/pkg/store"
15+
"github.com/lima-vm/lima/pkg/store/filenames"
16+
"github.com/sirupsen/logrus"
17+
)
18+
19+
func StopGracefully(inst *store.Instance) error {
20+
if inst.Status != store.StatusRunning {
21+
return fmt.Errorf("expected status %q, got %q (maybe use `limactl stop -f`?)", store.StatusRunning, inst.Status)
22+
}
23+
24+
begin := time.Now() // used for logrus propagation
25+
logrus.Infof("Sending SIGINT to hostagent process %d", inst.HostAgentPID)
26+
if err := osutil.SysKill(inst.HostAgentPID, osutil.SigInt); err != nil {
27+
logrus.Error(err)
28+
}
29+
30+
logrus.Info("Waiting for the host agent and the driver processes to shut down")
31+
return waitForHostAgentTermination(context.TODO(), inst, begin)
32+
}
33+
34+
func waitForHostAgentTermination(ctx context.Context, inst *store.Instance, begin time.Time) error {
35+
ctx2, cancel := context.WithTimeout(ctx, 3*time.Minute+10*time.Second)
36+
defer cancel()
37+
38+
var receivedExitingEvent bool
39+
onEvent := func(ev hostagentevents.Event) bool {
40+
if len(ev.Status.Errors) > 0 {
41+
logrus.Errorf("%+v", ev.Status.Errors)
42+
}
43+
if ev.Status.Exiting {
44+
receivedExitingEvent = true
45+
return true
46+
}
47+
return false
48+
}
49+
50+
haStdoutPath := filepath.Join(inst.Dir, filenames.HostAgentStdoutLog)
51+
haStderrPath := filepath.Join(inst.Dir, filenames.HostAgentStderrLog)
52+
53+
if err := hostagentevents.Watch(ctx2, haStdoutPath, haStderrPath, begin, onEvent); err != nil {
54+
return err
55+
}
56+
57+
if !receivedExitingEvent {
58+
return errors.New("did not receive an event with the \"exiting\" status")
59+
}
60+
61+
return nil
62+
}
63+
64+
func StopForcibly(inst *store.Instance) {
65+
if inst.DriverPID > 0 {
66+
logrus.Infof("Sending SIGKILL to the %s driver process %d", inst.VMType, inst.DriverPID)
67+
if err := osutil.SysKill(inst.DriverPID, osutil.SigKill); err != nil {
68+
logrus.Error(err)
69+
}
70+
} else {
71+
logrus.Infof("The %s driver process seems already stopped", inst.VMType)
72+
}
73+
74+
for _, d := range inst.AdditionalDisks {
75+
diskName := d.Name
76+
disk, err := store.InspectDisk(diskName)
77+
if err != nil {
78+
logrus.Warnf("Disk %q does not exist", diskName)
79+
continue
80+
}
81+
if err := disk.Unlock(); err != nil {
82+
logrus.Warnf("Failed to unlock disk %q. To use, run `limactl disk unlock %v`", diskName, diskName)
83+
}
84+
}
85+
86+
if inst.HostAgentPID > 0 {
87+
logrus.Infof("Sending SIGKILL to the host agent process %d", inst.HostAgentPID)
88+
if err := osutil.SysKill(inst.HostAgentPID, osutil.SigKill); err != nil {
89+
logrus.Error(err)
90+
}
91+
} else {
92+
logrus.Info("The host agent process seems already stopped")
93+
}
94+
95+
suffixesToBeRemoved := []string{".pid", ".sock", ".tmp"}
96+
logrus.Infof("Removing %s under %q", inst.Dir, strings.ReplaceAll(strings.Join(suffixesToBeRemoved, " "), ".", "*."))
97+
fi, err := os.ReadDir(inst.Dir)
98+
if err != nil {
99+
logrus.Error(err)
100+
return
101+
}
102+
for _, f := range fi {
103+
path := filepath.Join(inst.Dir, f.Name())
104+
for _, suffix := range suffixesToBeRemoved {
105+
if strings.HasSuffix(path, suffix) {
106+
logrus.Infof("Removing %q", path)
107+
if err := os.Remove(path); err != nil {
108+
logrus.Error(err)
109+
}
110+
}
111+
}
112+
}
113+
}

pkg/stop/stop.go

-24
This file was deleted.

0 commit comments

Comments
 (0)