Skip to content

Commit d2730be

Browse files
POC - LFX( TERM 2 ) - add Windows support with autounattend.xml generation
Signed-off-by: kishansinghifs1 <kishansingh956196@gmail.com>
1 parent 8f74e63 commit d2730be

8 files changed

Lines changed: 77 additions & 4 deletions

File tree

pkg/cidata/autounattend.xml.tmpl

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<unattend xmlns="urn:schemas-microsoft-com:unattend">
3+
<settings pass="oobeSystem">
4+
<component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
5+
<ComputerName>{{ .Hostname }}</ComputerName>
6+
<RegisteredOwner>{{ .User }}</RegisteredOwner>
7+
{{- if .TimeZone }}
8+
<TimeZone>{{ .TimeZone }}</TimeZone>
9+
{{- end }}
10+
</component>
11+
</settings>
12+
<!-- Lima SSH keys (placeholder, consumed by later Windows provisioning):
13+
{{- range .SSHPubKeys }}
14+
{{ . }}
15+
{{- end }}
16+
-->
17+
</unattend>

pkg/cidata/cidata.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,10 @@ func templateArgs(ctx context.Context, bootScripts bool, instDir, name string, i
359359
}
360360

361361
func GenerateCloudConfig(ctx context.Context, instDir, name string, instConfig *limatype.LimaYAML) error {
362+
if instConfig.OS != nil && *instConfig.OS == limatype.WINDOWS {
363+
return GenerateAutounattendXML(ctx, instDir, name, instConfig)
364+
}
365+
362366
args, err := templateArgs(ctx, false, instDir, name, instConfig, 0, 0, 0, "", false, false, false)
363367
if err != nil {
364368
return err
@@ -381,6 +385,25 @@ func GenerateCloudConfig(ctx context.Context, instDir, name string, instConfig *
381385
return os.WriteFile(filepath.Join(instDir, filenames.CloudConfig), config, 0o444)
382386
}
383387

388+
func GenerateAutounattendXML(ctx context.Context, instDir, name string, instConfig *limatype.LimaYAML) error {
389+
args, err := templateArgs(ctx, false, instDir, name, instConfig, 0, 0, 0, "", false, false, false)
390+
if err != nil {
391+
return err
392+
}
393+
394+
if err := ValidateTemplateArgs(args); err != nil {
395+
return err
396+
}
397+
398+
config, err := ExecuteTemplateAutounattendXML(args)
399+
if err != nil {
400+
return err
401+
}
402+
403+
os.RemoveAll(filepath.Join(instDir, filenames.AutounattendXML))
404+
return os.WriteFile(filepath.Join(instDir, filenames.AutounattendXML), config, 0o444)
405+
}
406+
384407
// GenerateISO9660 generates the cidata ISO9660 image (or directory, for noCloudInit)
385408
// in instDir. It returns the instance ID, which changes on every boot.
386409
func GenerateISO9660(ctx context.Context, drv driver.Driver, instDir, name string, instConfig *limatype.LimaYAML, udpDNSLocalPort, tcpDNSLocalPort int, guestAgentBinary, nerdctlArchive string, vsockPort int, virtioPort string, noCloudInit, rosettaEnabled, rosettaBinFmt bool) (string, error) {

pkg/cidata/template.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ import (
2020
//go:embed cidata.TEMPLATE.d
2121
var templateFS embed.FS
2222

23+
//go:embed autounattend.xml.tmpl
24+
var autounattendTemplate []byte
25+
2326
const templateFSRoot = "cidata.TEMPLATE.d"
2427

2528
type CACerts struct {
@@ -205,3 +208,11 @@ func ExecuteTemplateCIDataISO(args *TemplateArgs) ([]iso9660util.Entry, error) {
205208

206209
return layout, nil
207210
}
211+
212+
func ExecuteTemplateAutounattendXML(args *TemplateArgs) ([]byte, error) {
213+
if err := ValidateTemplateArgs(args); err != nil {
214+
return nil, err
215+
}
216+
217+
return textutil.ExecuteTemplate(string(autounattendTemplate), args)
218+
}

pkg/cidata/template_test.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,3 +168,22 @@ func TestTemplate9p(t *testing.T) {
168168
}
169169
}
170170
}
171+
172+
func TestAutounattendTemplate(t *testing.T) {
173+
args := &TemplateArgs{
174+
Name: "default",
175+
Hostname: "lima-win",
176+
User: "foo",
177+
UID: 501,
178+
Comment: "Foo",
179+
Home: "/home/foo.guest",
180+
Shell: "/bin/bash",
181+
SSHPubKeys: []string{
182+
"ssh-rsa dummy foo@example.com",
183+
},
184+
}
185+
config, err := ExecuteTemplateAutounattendXML(args)
186+
assert.NilError(t, err)
187+
assert.Assert(t, strings.Contains(string(config), "<ComputerName>lima-win</ComputerName>"))
188+
assert.Assert(t, strings.Contains(string(config), "ssh-rsa dummy"))
189+
}

pkg/limatype/filenames/filenames.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ const (
3636
CIDataISO = "cidata.iso"
3737
CIDataISODir = "cidata"
3838
CloudConfig = "cloud-config.yaml"
39+
AutounattendXML = "autounattend.xml"
3940
Image = "image" // downloaded VM image; renamed to Disk or ISO during setup
4041
ImageIPSW = "image.ipsw" // hardlink to Image for macOS guests
4142
Disk = "disk" // VM disk (or symlink to DiffDiskLegacy for migrated instances)

pkg/limatype/lima_yaml.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ const (
8080
LINUX OS = "Linux"
8181
DARWIN OS = "Darwin"
8282
FREEBSD OS = "FreeBSD"
83+
WINDOWS OS = "Windows"
8384

8485
X8664 Arch = "x86_64"
8586
AARCH64 Arch = "aarch64"
@@ -99,7 +100,7 @@ const (
99100
)
100101

101102
var (
102-
OSTypes = []OS{LINUX, DARWIN, FREEBSD}
103+
OSTypes = []OS{LINUX, DARWIN, FREEBSD, WINDOWS}
103104
ArchTypes = []Arch{X8664, AARCH64, ARMV7L, PPC64LE, RISCV64, S390X}
104105
MountTypes = []MountType{REVSSHFS, NINEP, VIRTIOFS, WSLMount}
105106
VMTypes = []VMType{QEMU, VZ, WSL2}
@@ -348,6 +349,8 @@ func NewOS(osname string) OS {
348349
return LINUX
349350
case "darwin":
350351
return DARWIN
352+
case "windows", "Windows":
353+
return WINDOWS
351354
default:
352355
logrus.Warnf("Unknown os: %s", osname)
353356
return osname

pkg/limayaml/validate.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ func Validate(y *limatype.LimaYAML, warn bool) error {
5050
}
5151

5252
switch *y.OS {
53-
case limatype.LINUX, limatype.DARWIN, limatype.FREEBSD:
53+
case limatype.LINUX, limatype.DARWIN, limatype.FREEBSD, limatype.WINDOWS:
5454
default:
5555
errs = errors.Join(errs, fmt.Errorf("field `os` must be one of %q; got %q", limatype.OSTypes, *y.OS))
5656
}

pkg/limayaml/validate_test.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -369,8 +369,7 @@ provision:
369369
err = Validate(y, false)
370370
t.Logf("Validation errors: %v", err)
371371

372-
assert.Error(t, err, "field `os` must be one of [\"Linux\" \"Darwin\" \"FreeBSD\"]; got \"windows\"\n"+
373-
"field `arch` must be one of [x86_64 aarch64 armv7l ppc64le riscv64 s390x]; got \"unsupported_arch\"\n"+
372+
assert.Error(t, err, "field `arch` must be one of [x86_64 aarch64 armv7l ppc64le riscv64 s390x]; got \"unsupported_arch\"\n"+
374373
"field `images` must be set\n"+
375374
"field `provision[0].mode` must one of \"system\", \"user\", \"boot\", \"data\", \"dependency\", \"ansible\", or \"yq\"\n"+
376375
"field `provision[1].path` must not be empty when mode is \"data\"")

0 commit comments

Comments
 (0)