Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
lima-vm
GitHub Repository: lima-vm/lima
Path: blob/master/cmd/limactl/guest-install.go
1645 views
1
// SPDX-FileCopyrightText: Copyright The Lima Authors
2
// SPDX-License-Identifier: Apache-2.0
3
4
package main
5
6
import (
7
"bytes"
8
"compress/gzip"
9
"context"
10
"errors"
11
"fmt"
12
"io"
13
"os"
14
"os/exec"
15
"path/filepath"
16
17
"github.com/sirupsen/logrus"
18
"github.com/spf13/cobra"
19
20
"github.com/lima-vm/lima/v2/pkg/cacheutil"
21
"github.com/lima-vm/lima/v2/pkg/limatype"
22
"github.com/lima-vm/lima/v2/pkg/limatype/filenames"
23
"github.com/lima-vm/lima/v2/pkg/store"
24
"github.com/lima-vm/lima/v2/pkg/usrlocalsharelima"
25
)
26
27
func newGuestInstallCommand() *cobra.Command {
28
guestInstallCommand := &cobra.Command{
29
Use: "guest-install INSTANCE",
30
Short: "Install guest components",
31
Args: WrapArgsError(cobra.MaximumNArgs(1)),
32
RunE: guestInstallAction,
33
ValidArgsFunction: cobra.NoFileCompletions,
34
Hidden: true,
35
}
36
return guestInstallCommand
37
}
38
39
func runCmd(ctx context.Context, name string, flags []string, args ...string) error {
40
cmd := exec.CommandContext(ctx, name, append(flags, args...)...)
41
cmd.Stdout = os.Stdout
42
cmd.Stderr = os.Stderr
43
logrus.Debugf("executing %v", cmd.Args)
44
return cmd.Run()
45
}
46
47
func shell(ctx context.Context, name string, flags []string, args ...string) (string, error) {
48
cmd := exec.CommandContext(ctx, name, append(flags, args...)...)
49
out, err := cmd.Output()
50
if err != nil {
51
return "", err
52
}
53
out = bytes.TrimSuffix(out, []byte{'\n'})
54
return string(out), nil
55
}
56
57
func guestInstallAction(cmd *cobra.Command, args []string) error {
58
instName := DefaultInstanceName
59
if len(args) > 0 {
60
instName = args[0]
61
}
62
63
inst, err := store.Inspect(cmd.Context(), instName)
64
if err != nil {
65
return err
66
}
67
if inst.Status == limatype.StatusStopped {
68
return fmt.Errorf("instance %q is stopped, run `limactl start %s` to start the instance", instName, instName)
69
}
70
71
ctx := cmd.Context()
72
73
sshExe := "ssh"
74
sshConfig := filepath.Join(inst.Dir, filenames.SSHConfig)
75
sshFlags := []string{"-F", sshConfig}
76
77
scpExe := "scp"
78
scpFlags := sshFlags
79
80
hostname := fmt.Sprintf("lima-%s", inst.Name)
81
prefix := *inst.Config.GuestInstallPrefix
82
83
// lima-guestagent
84
guestAgentBinary, err := usrlocalsharelima.GuestAgentBinary(*inst.Config.OS, *inst.Config.Arch)
85
if err != nil {
86
return err
87
}
88
guestAgentFilename := filepath.Base(guestAgentBinary)
89
if _, err := os.Stat(guestAgentBinary); err != nil {
90
if !errors.Is(err, os.ErrNotExist) {
91
return err
92
}
93
compressedGuestAgent, err := os.Open(guestAgentBinary + ".gz")
94
if err != nil {
95
return err
96
}
97
defer compressedGuestAgent.Close()
98
tmpGuestAgent, err := os.CreateTemp("", "lima-guestagent-")
99
if err != nil {
100
return err
101
}
102
logrus.Debugf("Decompressing %s.gz", guestAgentBinary)
103
guestAgent, err := gzip.NewReader(compressedGuestAgent)
104
if err != nil {
105
return err
106
}
107
defer guestAgent.Close()
108
_, err = io.Copy(tmpGuestAgent, guestAgent)
109
if err != nil {
110
return err
111
}
112
tmpGuestAgent.Close()
113
guestAgentBinary = tmpGuestAgent.Name()
114
defer os.RemoveAll(guestAgentBinary)
115
}
116
tmpname := "lima-guestagent"
117
tmp, err := shell(ctx, sshExe, sshFlags, hostname, "mktemp", "-t", "lima-guestagent.XXXXXX")
118
if err != nil {
119
return err
120
}
121
bin := prefix + "/bin/lima-guestagent"
122
logrus.Infof("Copying %q to %s:%s", guestAgentFilename, inst.Name, tmpname)
123
scpArgs := []string{guestAgentBinary, hostname + ":" + tmp}
124
if err := runCmd(ctx, scpExe, scpFlags, scpArgs...); err != nil {
125
return nil
126
}
127
logrus.Infof("Installing %s to %s", tmpname, bin)
128
sshArgs := []string{hostname, "sudo", "install", "-m", "755", tmp, bin}
129
if err := runCmd(ctx, sshExe, sshFlags, sshArgs...); err != nil {
130
return nil
131
}
132
_, _ = shell(ctx, sshExe, sshFlags, hostname, "rm", tmp)
133
134
// nerdctl-full.tgz
135
nerdctlFilename := cacheutil.NerdctlArchive(inst.Config)
136
if nerdctlFilename != "" {
137
nerdctlArchive, err := cacheutil.EnsureNerdctlArchiveCache(cmd.Context(), inst.Config, false)
138
if err != nil {
139
return err
140
}
141
tmpname := "nerdctl-full.tgz"
142
tmp, err := shell(ctx, sshExe, sshFlags, hostname, "mktemp", "-t", "nerdctl-full.XXXXXX.tgz")
143
if err != nil {
144
return err
145
}
146
logrus.Infof("Copying %q to %s:%s", nerdctlFilename, inst.Name, tmpname)
147
scpArgs := []string{nerdctlArchive, hostname + ":" + tmp}
148
if err := runCmd(ctx, scpExe, scpFlags, scpArgs...); err != nil {
149
return nil
150
}
151
logrus.Infof("Installing %s in %s", tmpname, prefix)
152
sshArgs := []string{hostname, "sudo", "tar", "Cxzf", prefix, tmp}
153
if err := runCmd(ctx, sshExe, sshFlags, sshArgs...); err != nil {
154
return nil
155
}
156
_, _ = shell(ctx, sshExe, sshFlags, hostname, "rm", tmp)
157
}
158
159
return nil
160
}
161
162