Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
lima-vm
GitHub Repository: lima-vm/lima
Path: blob/master/cmd/limactl/guest-install.go
2635 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
"fmt"
11
"io"
12
"os"
13
"os/exec"
14
"path/filepath"
15
"strings"
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/usrlocal"
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 := usrlocal.GuestAgentBinary(*inst.Config.OS, *inst.Config.Arch)
85
if err != nil {
86
return err
87
}
88
guestAgentFilename := filepath.Base(guestAgentBinary)
89
if filepath.Ext(guestAgentBinary) == ".gz" {
90
compressedGuestAgent, err := os.Open(guestAgentBinary)
91
if err != nil {
92
return err
93
}
94
defer compressedGuestAgent.Close()
95
tmpGuestAgent, err := os.CreateTemp("", "lima-guestagent-")
96
if err != nil {
97
return err
98
}
99
logrus.Debugf("Decompressing %s", guestAgentBinary)
100
guestAgent, err := gzip.NewReader(compressedGuestAgent)
101
if err != nil {
102
return err
103
}
104
defer guestAgent.Close()
105
_, err = io.Copy(tmpGuestAgent, guestAgent)
106
if err != nil {
107
return err
108
}
109
tmpGuestAgent.Close()
110
guestAgentBinary = tmpGuestAgent.Name()
111
defer os.RemoveAll(guestAgentBinary)
112
guestAgentFilename = strings.TrimSuffix(guestAgentFilename, ".gz")
113
}
114
tmpname := "lima-guestagent"
115
tmp, err := shell(ctx, sshExe, sshFlags, hostname, "mktemp", "-t", "lima-guestagent.XXXXXX")
116
if err != nil {
117
return err
118
}
119
bin := prefix + "/bin/lima-guestagent"
120
logrus.Infof("Copying %q to %s:%s", guestAgentFilename, inst.Name, tmpname)
121
scpArgs := []string{guestAgentBinary, hostname + ":" + tmp}
122
if err := runCmd(ctx, scpExe, scpFlags, scpArgs...); err != nil {
123
return nil
124
}
125
logrus.Infof("Installing %s to %s", tmpname, bin)
126
sshArgs := []string{hostname, "sudo", "install", "-m", "755", tmp, bin}
127
if err := runCmd(ctx, sshExe, sshFlags, sshArgs...); err != nil {
128
return nil
129
}
130
_, _ = shell(ctx, sshExe, sshFlags, hostname, "rm", tmp)
131
132
// nerdctl-full.tgz
133
nerdctlFilename := cacheutil.NerdctlArchive(inst.Config)
134
if nerdctlFilename != "" {
135
nerdctlArchive, err := cacheutil.EnsureNerdctlArchiveCache(cmd.Context(), inst.Config, false)
136
if err != nil {
137
return err
138
}
139
tmpname := "nerdctl-full.tgz"
140
tmp, err := shell(ctx, sshExe, sshFlags, hostname, "mktemp", "-t", "nerdctl-full.XXXXXX.tgz")
141
if err != nil {
142
return err
143
}
144
logrus.Infof("Copying %q to %s:%s", nerdctlFilename, inst.Name, tmpname)
145
scpArgs := []string{nerdctlArchive, hostname + ":" + tmp}
146
if err := runCmd(ctx, scpExe, scpFlags, scpArgs...); err != nil {
147
return nil
148
}
149
logrus.Infof("Installing %s in %s", tmpname, prefix)
150
sshArgs := []string{hostname, "sudo", "tar", "Cxzf", prefix, tmp}
151
if err := runCmd(ctx, sshExe, sshFlags, sshArgs...); err != nil {
152
return nil
153
}
154
_, _ = shell(ctx, sshExe, sshFlags, hostname, "rm", tmp)
155
}
156
157
return nil
158
}
159
160