Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions pkg/cidata/autounattend.xml.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<unattend xmlns="urn:schemas-microsoft-com:unattend">
<settings pass="oobeSystem">
<component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
<ComputerName>{{ .Hostname }}</ComputerName>
<RegisteredOwner>{{ .User }}</RegisteredOwner>
{{- if .TimeZone }}
<TimeZone>{{ .TimeZone }}</TimeZone>
{{- end }}
</component>
</settings>
<!-- Lima SSH keys (placeholder, consumed by later Windows provisioning):
{{- range .SSHPubKeys }}
{{ . }}
{{- end }}
-->
</unattend>
23 changes: 23 additions & 0 deletions pkg/cidata/cidata.go
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,10 @@ func templateArgs(ctx context.Context, bootScripts bool, instDir, name string, i
}

func GenerateCloudConfig(ctx context.Context, instDir, name string, instConfig *limatype.LimaYAML) error {
if instConfig.OS != nil && *instConfig.OS == limatype.WINDOWS {
return GenerateAutounattendXML(ctx, instDir, name, instConfig)
}

args, err := templateArgs(ctx, false, instDir, name, instConfig, 0, 0, 0, "", false, false, false)
if err != nil {
return err
Expand All @@ -381,6 +385,25 @@ func GenerateCloudConfig(ctx context.Context, instDir, name string, instConfig *
return os.WriteFile(filepath.Join(instDir, filenames.CloudConfig), config, 0o444)
}

func GenerateAutounattendXML(ctx context.Context, instDir, name string, instConfig *limatype.LimaYAML) error {
args, err := templateArgs(ctx, false, instDir, name, instConfig, 0, 0, 0, "", false, false, false)
if err != nil {
return err
}

if err := ValidateTemplateArgs(args); err != nil {
return err
}

config, err := ExecuteTemplateAutounattendXML(args)
if err != nil {
return err
}

os.RemoveAll(filepath.Join(instDir, filenames.AutounattendXML))
return os.WriteFile(filepath.Join(instDir, filenames.AutounattendXML), config, 0o444)
}

// GenerateISO9660 generates the cidata ISO9660 image (or directory, for noCloudInit)
// in instDir. It returns the instance ID, which changes on every boot.
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) {
Expand Down
11 changes: 11 additions & 0 deletions pkg/cidata/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ import (
//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 {
Expand Down Expand Up @@ -205,3 +208,11 @@ func ExecuteTemplateCIDataISO(args *TemplateArgs) ([]iso9660util.Entry, error) {

return layout, nil
}

func ExecuteTemplateAutounattendXML(args *TemplateArgs) ([]byte, error) {
if err := ValidateTemplateArgs(args); err != nil {
return nil, err
}

return textutil.ExecuteTemplate(string(autounattendTemplate), args)
}
19 changes: 19 additions & 0 deletions pkg/cidata/template_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,3 +168,22 @@ func TestTemplate9p(t *testing.T) {
}
}
}

func TestAutounattendTemplate(t *testing.T) {
args := &TemplateArgs{
Name: "default",
Hostname: "lima-win",
User: "foo",
UID: 501,
Comment: "Foo",
Home: "/home/foo.guest",
Shell: "/bin/bash",
SSHPubKeys: []string{
"ssh-rsa dummy foo@example.com",
},
}
config, err := ExecuteTemplateAutounattendXML(args)
assert.NilError(t, err)
assert.Assert(t, strings.Contains(string(config), "<ComputerName>lima-win</ComputerName>"))
assert.Assert(t, strings.Contains(string(config), "ssh-rsa dummy"))
}
1 change: 1 addition & 0 deletions pkg/limatype/filenames/filenames.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ const (
CIDataISO = "cidata.iso"
CIDataISODir = "cidata"
CloudConfig = "cloud-config.yaml"
AutounattendXML = "autounattend.xml"
Image = "image" // downloaded VM image; renamed to Disk or ISO during setup
ImageIPSW = "image.ipsw" // hardlink to Image for macOS guests
Disk = "disk" // VM disk (or symlink to DiffDiskLegacy for migrated instances)
Expand Down
5 changes: 4 additions & 1 deletion pkg/limatype/lima_yaml.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ const (
LINUX OS = "Linux"
DARWIN OS = "Darwin"
FREEBSD OS = "FreeBSD"
WINDOWS OS = "Windows"

X8664 Arch = "x86_64"
AARCH64 Arch = "aarch64"
Expand All @@ -99,7 +100,7 @@ const (
)

var (
OSTypes = []OS{LINUX, DARWIN, FREEBSD}
OSTypes = []OS{LINUX, DARWIN, FREEBSD, WINDOWS}
ArchTypes = []Arch{X8664, AARCH64, ARMV7L, PPC64LE, RISCV64, S390X}
MountTypes = []MountType{REVSSHFS, NINEP, VIRTIOFS, WSLMount}
VMTypes = []VMType{QEMU, VZ, WSL2}
Expand Down Expand Up @@ -348,6 +349,8 @@ func NewOS(osname string) OS {
return LINUX
case "darwin":
return DARWIN
case "windows", "Windows":
return WINDOWS
default:
logrus.Warnf("Unknown os: %s", osname)
return osname
Expand Down
2 changes: 1 addition & 1 deletion pkg/limayaml/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ func Validate(y *limatype.LimaYAML, warn bool) error {
}

switch *y.OS {
case limatype.LINUX, limatype.DARWIN, limatype.FREEBSD:
case limatype.LINUX, limatype.DARWIN, limatype.FREEBSD, limatype.WINDOWS:
default:
errs = errors.Join(errs, fmt.Errorf("field `os` must be one of %q; got %q", limatype.OSTypes, *y.OS))
}
Expand Down
3 changes: 1 addition & 2 deletions pkg/limayaml/validate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -369,8 +369,7 @@ provision:
err = Validate(y, false)
t.Logf("Validation errors: %v", err)

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