Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
lima-vm
GitHub Repository: lima-vm/lima
Path: blob/master/pkg/cidata/template.go
2601 views
1
// SPDX-FileCopyrightText: Copyright The Lima Authors
2
// SPDX-License-Identifier: Apache-2.0
3
4
package cidata
5
6
import (
7
"bytes"
8
"embed"
9
"errors"
10
"fmt"
11
"io/fs"
12
"path"
13
14
"github.com/lima-vm/lima/v2/pkg/identifiers"
15
"github.com/lima-vm/lima/v2/pkg/iso9660util"
16
"github.com/lima-vm/lima/v2/pkg/textutil"
17
)
18
19
//go:embed cidata.TEMPLATE.d
20
var templateFS embed.FS
21
22
const templateFSRoot = "cidata.TEMPLATE.d"
23
24
type CACerts struct {
25
RemoveDefaults *bool
26
Trusted []Cert
27
}
28
29
type Cert struct {
30
Lines []string
31
}
32
33
type Containerd struct {
34
System bool
35
User bool
36
Archive string
37
}
38
type Network struct {
39
MACAddress string
40
Interface string
41
Metric uint32
42
}
43
type Mount struct {
44
Tag string
45
MountPoint string // abs path, accessible by the User
46
Type string
47
Options string
48
}
49
type BootCmds struct {
50
Lines []string
51
}
52
53
type DataFile struct {
54
FileName string
55
Overwrite string
56
Owner string
57
Path string
58
Permissions string
59
}
60
61
type YQProvision struct {
62
FileName string
63
Format string
64
Owner string
65
Path string
66
Permissions string
67
}
68
69
type Disk struct {
70
Name string
71
Device string
72
Format bool
73
FSType string
74
FSArgs []string
75
}
76
type TemplateArgs struct {
77
Debug bool
78
Name string // instance name
79
Hostname string // instance hostname
80
IID string // instance id
81
User string // user name
82
Comment string // user information
83
Home string // home directory
84
Shell string // login shell
85
UID uint32
86
SSHPubKeys []string
87
Mounts []Mount
88
MountType string
89
Disks []Disk
90
GuestInstallPrefix string
91
UpgradePackages bool
92
Containerd Containerd
93
Networks []Network
94
SlirpNICName string
95
SlirpGateway string
96
SlirpDNS string
97
SlirpIPAddress string
98
UDPDNSLocalPort int
99
TCPDNSLocalPort int
100
Env map[string]string
101
Param map[string]string
102
BootScripts bool
103
DataFiles []DataFile
104
YQProvisions []YQProvision
105
DNSAddresses []string
106
CACerts CACerts
107
HostHomeMountPoint string
108
BootCmds []BootCmds
109
RosettaEnabled bool
110
RosettaBinFmt bool
111
SkipDefaultDependencyResolution bool
112
VMType string
113
VSockPort int
114
VirtioPort string
115
Plain bool
116
TimeZone string
117
NoCloudInit bool
118
}
119
120
func ValidateTemplateArgs(args *TemplateArgs) error {
121
if err := identifiers.Validate(args.Name); err != nil {
122
return err
123
}
124
// args.User is intentionally not validated here; the user can override with any name they want
125
// limayaml.FillDefault will validate the default (local) username, but not an explicit setting
126
if args.User == "root" {
127
return errors.New("field User must not be \"root\"")
128
}
129
if args.UID == 0 {
130
return errors.New("field UID must not be 0")
131
}
132
if args.Home == "" {
133
return errors.New("field Home must be set")
134
}
135
if args.Shell == "" {
136
return errors.New("field Shell must be set")
137
}
138
if len(args.SSHPubKeys) == 0 {
139
return errors.New("field SSHPubKeys must be set")
140
}
141
for i, m := range args.Mounts {
142
f := m.MountPoint
143
if !path.IsAbs(f) {
144
return fmt.Errorf("field mounts[%d] must be absolute, got %q", i, f)
145
}
146
}
147
return nil
148
}
149
150
func ExecuteTemplateCloudConfig(args *TemplateArgs) ([]byte, error) {
151
if err := ValidateTemplateArgs(args); err != nil {
152
return nil, err
153
}
154
155
userData, err := templateFS.ReadFile(path.Join(templateFSRoot, "user-data"))
156
if err != nil {
157
return nil, err
158
}
159
160
cloudConfigYaml := string(userData)
161
return textutil.ExecuteTemplate(cloudConfigYaml, args)
162
}
163
164
func ExecuteTemplateCIDataISO(args *TemplateArgs) ([]iso9660util.Entry, error) {
165
if err := ValidateTemplateArgs(args); err != nil {
166
return nil, err
167
}
168
169
fsys, err := fs.Sub(templateFS, templateFSRoot)
170
if err != nil {
171
return nil, err
172
}
173
174
var layout []iso9660util.Entry
175
walkFn := func(path string, d fs.DirEntry, walkErr error) error {
176
if walkErr != nil {
177
return walkErr
178
}
179
if d.IsDir() {
180
return nil
181
}
182
if !d.Type().IsRegular() {
183
return fmt.Errorf("got non-regular file %q", path)
184
}
185
templateB, err := fs.ReadFile(fsys, path)
186
if err != nil {
187
return err
188
}
189
b, err := textutil.ExecuteTemplate(string(templateB), args)
190
if err != nil {
191
return err
192
}
193
layout = append(layout, iso9660util.Entry{
194
Path: path,
195
Reader: bytes.NewReader(b),
196
})
197
return nil
198
}
199
200
if err := fs.WalkDir(fsys, ".", walkFn); err != nil {
201
return nil, err
202
}
203
204
return layout, nil
205
}
206
207