From 59e7c0ec5bc754fffdaaaf875d051fb4a279664b Mon Sep 17 00:00:00 2001 From: Norio Nomura Date: Wed, 4 Sep 2024 10:34:26 +0900 Subject: [PATCH] limayaml: support template expansion in `.mounts[].location` and `.mounts[].mountPoint` Signed-off-by: Norio Nomura --- examples/default.yaml | 2 ++ pkg/limayaml/defaults.go | 10 ++++++++++ pkg/limayaml/defaults_test.go | 12 ++++++++++++ pkg/limayaml/validate.go | 10 ++++++++++ pkg/limayaml/validate_test.go | 4 ++++ 5 files changed, 38 insertions(+) diff --git a/examples/default.yaml b/examples/default.yaml index 4df6395689a..8c31da87990 100644 --- a/examples/default.yaml +++ b/examples/default.yaml @@ -50,6 +50,8 @@ memory: null disk: null # Expose host directories to the guest, the mount point might be accessible from all UIDs in the guest +# "location" can use these template variables: {{.Home}}, {{.Dir}}, {{.Name}}, {{.UID}}, {{.User}}, and {{.Param.Key}}. +# "mountPoint" can use these template variables: {{.Home}}, {{.Name}}, {{.UID}}, {{.User}}, and {{.Param.Key}} # 🟢 Builtin default: null (Mount nothing) # 🔵 This file: Mount the home as read-only, /tmp/lima as writable mounts: diff --git a/pkg/limayaml/defaults.go b/pkg/limayaml/defaults.go index 8ac8c26c7bd..d3cc7ef8e3c 100644 --- a/pkg/limayaml/defaults.go +++ b/pkg/limayaml/defaults.go @@ -577,6 +577,16 @@ func FillDefault(y, d, o *LimaYAML, filePath string) { mounts := make([]Mount, 0, len(d.Mounts)+len(y.Mounts)+len(o.Mounts)) location := make(map[string]int) for _, mount := range append(append(d.Mounts, y.Mounts...), o.Mounts...) { + if out, err := executeHostTemplate(mount.Location, instDir, y.Param); err == nil { + mount.Location = out.String() + } else { + logrus.WithError(err).Warnf("Couldn't process mount location %q as a template", mount.Location) + } + if out, err := executeGuestTemplate(mount.MountPoint, instDir, y.Param); err == nil { + mount.MountPoint = out.String() + } else { + logrus.WithError(err).Warnf("Couldn't process mount point %q as a template", mount.MountPoint) + } if i, ok := location[mount.Location]; ok { if mount.SSHFS.Cache != nil { mounts[i].SSHFS.Cache = mount.SSHFS.Cache diff --git a/pkg/limayaml/defaults_test.go b/pkg/limayaml/defaults_test.go index 8f49816a157..16fff19415d 100644 --- a/pkg/limayaml/defaults_test.go +++ b/pkg/limayaml/defaults_test.go @@ -131,6 +131,7 @@ func TestFillDefault(t *testing.T) { }, Mounts: []Mount{ {Location: "/tmp"}, + {Location: "{{.Dir}}/{{.Param.ONE}}", MountPoint: "/mnt/{{.Param.ONE}}"}, }, MountType: ptr.Of(NINEP), Provision: []Provision{ @@ -214,6 +215,17 @@ func TestFillDefault(t *testing.T) { expect.Mounts[0].NineP.Cache = ptr.Of(Default9pCacheForRO) expect.Mounts[0].Virtiofs.QueueSize = nil // Only missing Mounts field is Writable, and the default value is also the null value: false + expect.Mounts[1].Location = fmt.Sprintf("%s/%s", instDir, y.Param["ONE"]) + expect.Mounts[1].MountPoint = fmt.Sprintf("/mnt/%s", y.Param["ONE"]) + expect.Mounts[1].Writable = ptr.Of(false) + expect.Mounts[1].SSHFS.Cache = ptr.Of(true) + expect.Mounts[1].SSHFS.FollowSymlinks = ptr.Of(false) + expect.Mounts[1].SSHFS.SFTPDriver = ptr.Of("") + expect.Mounts[1].NineP.SecurityModel = ptr.Of(Default9pSecurityModel) + expect.Mounts[1].NineP.ProtocolVersion = ptr.Of(Default9pProtocolVersion) + expect.Mounts[1].NineP.Msize = ptr.Of(Default9pMsize) + expect.Mounts[1].NineP.Cache = ptr.Of(Default9pCacheForRO) + expect.Mounts[1].Virtiofs.QueueSize = nil expect.MountType = ptr.Of(NINEP) diff --git a/pkg/limayaml/validate.go b/pkg/limayaml/validate.go index 8eb719ede32..0cfee5e7a72 100644 --- a/pkg/limayaml/validate.go +++ b/pkg/limayaml/validate.go @@ -426,6 +426,16 @@ func ValidateParamIsUsed(y *LimaYAML) error { break } } + for _, p := range y.Mounts { + if re.MatchString(p.Location) { + keyIsUsed = true + break + } + if re.MatchString(p.MountPoint) { + keyIsUsed = true + break + } + } if !keyIsUsed { return fmt.Errorf("field `param` key %q is not used in any provision, probe, copyToHost, or portForward", key) } diff --git a/pkg/limayaml/validate_test.go b/pkg/limayaml/validate_test.go index 9be1b3a63e9..347ee7df96d 100644 --- a/pkg/limayaml/validate_test.go +++ b/pkg/limayaml/validate_test.go @@ -38,6 +38,8 @@ func TestValidateParamIsUsed(t *testing.T) { assert.Error(t, err, "field `param` key \"name\" is not used in any provision, probe, copyToHost, or portForward") fieldsUsingParam := []string{ + `mounts: [{"location": "/tmp/{{ .Param.name }}"}]`, + `mounts: [{"location": "/tmp", mountPoint: "/tmp/{{ .Param.name }}"}]`, `provision: [{"script": "echo {{ .Param.name }}"}]`, `probes: [{"script": "echo {{ .Param.name }}"}]`, `copyToHost: [{"guest": "/tmp/{{ .Param.name }}", "host": "/tmp"}]`, @@ -55,6 +57,8 @@ func TestValidateParamIsUsed(t *testing.T) { rootfulYaml := `param: rootful: true` fieldsUsingIfParamRootfulTrue := []string{ + `mounts: [{"location": "/tmp/{{if eq .Param.rootful \"true\"}}rootful{{else}}rootless{{end}}", "mountPoint": "/tmp"}]`, + `mounts: [{"location": "/tmp", "mountPoint": "/tmp/{{if eq .Param.rootful \"true\"}}rootful{{else}}rootless{{end}}"}]`, `provision: [{"script": "echo {{if eq .Param.rootful \"true\"}}rootful{{else}}rootless{{end}}"}]`, `probes: [{"script": "echo {{if eq .Param.rootful \"true\"}}rootful{{else}}rootless{{end}}"}]`, `copyToHost: [{"guest": "/tmp/{{if eq .Param.rootful \"true\"}}rootful{{else}}rootless{{end}}", "host": "/tmp"}]`,