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