88 "fmt"
99 "net"
1010 "os"
11+ "os/user"
1112 "path/filepath"
1213 "runtime"
1314 "slices"
@@ -18,11 +19,13 @@ import (
1819 "github.com/coreos/go-semver/semver"
1920 "github.com/docker/go-units"
2021 "github.com/goccy/go-yaml"
22+ "github.com/lima-vm/lima/pkg/version"
2123 "github.com/pbnjay/memory"
2224 "github.com/sirupsen/logrus"
2325 "golang.org/x/sys/cpu"
2426
2527 "github.com/lima-vm/lima/pkg/identifierutil"
28+ . "github.com/lima-vm/lima/pkg/must"
2629 "github.com/lima-vm/lima/pkg/networks"
2730 "github.com/lima-vm/lima/pkg/osutil"
2831 "github.com/lima-vm/lima/pkg/ptr"
@@ -43,7 +46,12 @@ const (
4346 DefaultVirtiofsQueueSize int = 1024
4447)
4548
46- var IPv4loopback1 = net .IPv4 (127 , 0 , 0 , 1 )
49+ var (
50+ IPv4loopback1 = net .IPv4 (127 , 0 , 0 , 1 )
51+
52+ userHomeDir = Must (os .UserHomeDir ())
53+ currentUser = Must (user .Current ())
54+ )
4755
4856func defaultCPUType () CPUType {
4957 cpuType := map [Arch ]string {
@@ -171,17 +179,58 @@ func defaultGuestInstallPrefix() string {
171179// - Networks are appended in d, y, o order
172180// - DNS are picked from the highest priority where DNS is not empty.
173181// - CACertificates Files and Certs are uniquely appended in d, y, o order
174- func FillDefault (y , d , o * LimaYAML , filePath string ) {
182+ func FillDefault (y , d , o * LimaYAML , filePath string , warn bool ) {
175183 instDir := filepath .Dir (filePath )
176184
177185 // existingLimaVersion can be empty if the instance was created with Lima prior to v0.20,
178186 // or, when editing a template file without an instance (`limactl edit foo.yaml`)
179187 var existingLimaVersion string
180- limaVersionFile := filepath .Join (instDir , filenames .LimaVersion )
181- if b , err := os .ReadFile (limaVersionFile ); err == nil {
182- existingLimaVersion = strings .TrimSpace (string (b ))
183- } else if ! errors .Is (err , os .ErrNotExist ) {
184- logrus .WithError (err ).Warnf ("Failed to read %q" , limaVersionFile )
188+ if warn {
189+ // If warnings are enabled, then a new instance is being created using the current Lima version
190+ existingLimaVersion = version .Version
191+ } else {
192+ limaVersionFile := filepath .Join (instDir , filenames .LimaVersion )
193+ if b , err := os .ReadFile (limaVersionFile ); err == nil {
194+ existingLimaVersion = strings .TrimSpace (string (b ))
195+ } else if ! errors .Is (err , os .ErrNotExist ) {
196+ logrus .WithError (err ).Warnf ("Failed to read %q" , limaVersionFile )
197+ }
198+ }
199+
200+ if y .User .Username == nil {
201+ y .User .Username = d .User .Username
202+ }
203+ if y .User .HomeDir == nil {
204+ y .User .HomeDir = d .User .HomeDir
205+ }
206+ if y .User .UID == nil {
207+ y .User .UID = d .User .UID
208+ }
209+ if o .User .Username != nil {
210+ y .User .Username = o .User .Username
211+ }
212+ if o .User .HomeDir != nil {
213+ y .User .HomeDir = o .User .HomeDir
214+ }
215+ if o .User .UID != nil {
216+ y .User .UID = o .User .UID
217+ }
218+ if y .User .Username == nil {
219+ y .User .Username = ptr .Of (osutil .LimaUser (existingLimaVersion , warn ).Username )
220+ warn = false
221+ }
222+ if y .User .HomeDir == nil {
223+ y .User .HomeDir = ptr .Of (osutil .LimaUser (existingLimaVersion , warn ).HomeDir )
224+ warn = false
225+ }
226+ if y .User .UID == nil {
227+ y .User .UID = ptr .Of (osutil .LimaUser (existingLimaVersion , warn ).Uid )
228+ // warn = false
229+ }
230+ if out , err := executeGuestTemplate (* y .User .HomeDir , instDir , y .User , y .Param ); err == nil {
231+ y .User .HomeDir = ptr .Of (out .String ())
232+ } else {
233+ logrus .WithError (err ).Warnf ("Couldn't process `user.homeDir` value %q as a template" , * y .User .HomeDir )
185234 }
186235
187236 if y .VMType == nil {
@@ -406,7 +455,7 @@ func FillDefault(y, d, o *LimaYAML, filePath string) {
406455 if provision .Mode == ProvisionModeDependency && provision .SkipDefaultDependencyResolution == nil {
407456 provision .SkipDefaultDependencyResolution = ptr .Of (false )
408457 }
409- if out , err := executeGuestTemplate (provision .Script , instDir , y .Param ); err == nil {
458+ if out , err := executeGuestTemplate (provision .Script , instDir , y .User , y . Param ); err == nil {
410459 provision .Script = out .String ()
411460 } else {
412461 logrus .WithError (err ).Warnf ("Couldn't process provisioning script %q as a template" , provision .Script )
@@ -477,7 +526,7 @@ func FillDefault(y, d, o *LimaYAML, filePath string) {
477526 if probe .Description == "" {
478527 probe .Description = fmt .Sprintf ("user probe %d/%d" , i + 1 , len (y .Probes ))
479528 }
480- if out , err := executeGuestTemplate (probe .Script , instDir , y .Param ); err == nil {
529+ if out , err := executeGuestTemplate (probe .Script , instDir , y .User , y . Param ); err == nil {
481530 probe .Script = out .String ()
482531 } else {
483532 logrus .WithError (err ).Warnf ("Couldn't process probing script %q as a template" , probe .Script )
@@ -486,13 +535,13 @@ func FillDefault(y, d, o *LimaYAML, filePath string) {
486535
487536 y .PortForwards = append (append (o .PortForwards , y .PortForwards ... ), d .PortForwards ... )
488537 for i := range y .PortForwards {
489- FillPortForwardDefaults (& y .PortForwards [i ], instDir , y .Param )
538+ FillPortForwardDefaults (& y .PortForwards [i ], instDir , y .User , y . Param )
490539 // After defaults processing the singular HostPort and GuestPort values should not be used again.
491540 }
492541
493542 y .CopyToHost = append (append (o .CopyToHost , y .CopyToHost ... ), d .CopyToHost ... )
494543 for i := range y .CopyToHost {
495- FillCopyToHostDefaults (& y .CopyToHost [i ], instDir , y .Param )
544+ FillCopyToHostDefaults (& y .CopyToHost [i ], instDir , y .User , y . Param )
496545 }
497546
498547 if y .HostResolver .Enabled == nil {
@@ -621,7 +670,7 @@ func FillDefault(y, d, o *LimaYAML, filePath string) {
621670 logrus .WithError (err ).Warnf ("Couldn't process mount location %q as a template" , mount .Location )
622671 }
623672 if mount .MountPoint != nil {
624- if out , err := executeGuestTemplate (* mount .MountPoint , instDir , y .Param ); err == nil {
673+ if out , err := executeGuestTemplate (* mount .MountPoint , instDir , y .User , y . Param ); err == nil {
625674 mount .MountPoint = ptr .Of (out .String ())
626675 } else {
627676 logrus .WithError (err ).Warnf ("Couldn't process mount point %q as a template" , * mount .MountPoint )
@@ -811,17 +860,16 @@ func fixUpForPlainMode(y *LimaYAML) {
811860 y .TimeZone = ptr .Of ("" )
812861}
813862
814- func executeGuestTemplate (format , instDir string , param map [string ]string ) (bytes.Buffer , error ) {
863+ func executeGuestTemplate (format , instDir string , user User , param map [string ]string ) (bytes.Buffer , error ) {
815864 tmpl , err := template .New ("" ).Parse (format )
816865 if err == nil {
817- user , _ := osutil .LimaUser (false )
818866 name := filepath .Base (instDir )
819867 data := map [string ]interface {}{
820- "Home" : fmt .Sprintf ("/home/%s.linux" , user .Username ),
821868 "Name" : name ,
822869 "Hostname" : identifierutil .HostnameFromInstName (name ), // TODO: support customization
823- "UID" : user .Uid ,
824- "User" : user .Username ,
870+ "UID" : * user .UID ,
871+ "User" : * user .Username ,
872+ "Home" : * user .HomeDir ,
825873 "Param" : param ,
826874 }
827875 var out bytes.Buffer
@@ -835,16 +883,14 @@ func executeGuestTemplate(format, instDir string, param map[string]string) (byte
835883func executeHostTemplate (format , instDir string , param map [string ]string ) (bytes.Buffer , error ) {
836884 tmpl , err := template .New ("" ).Parse (format )
837885 if err == nil {
838- user , _ := osutil .LimaUser (false )
839- home , _ := os .UserHomeDir ()
840886 limaHome , _ := dirnames .LimaDir ()
841887 data := map [string ]interface {}{
842888 "Dir" : instDir ,
843- "Home" : home ,
844889 "Name" : filepath .Base (instDir ),
845890 // TODO: add hostname fields for the host and the guest
846- "UID" : user .Uid ,
847- "User" : user .Username ,
891+ "UID" : currentUser .Uid ,
892+ "User" : currentUser .Username ,
893+ "Home" : userHomeDir ,
848894 "Param" : param ,
849895
850896 "Instance" : filepath .Base (instDir ), // DEPRECATED, use `{{.Name}}`
@@ -858,7 +904,7 @@ func executeHostTemplate(format, instDir string, param map[string]string) (bytes
858904 return bytes.Buffer {}, err
859905}
860906
861- func FillPortForwardDefaults (rule * PortForward , instDir string , param map [string ]string ) {
907+ func FillPortForwardDefaults (rule * PortForward , instDir string , user User , param map [string ]string ) {
862908 if rule .Proto == "" {
863909 rule .Proto = ProtoTCP
864910 }
@@ -890,7 +936,7 @@ func FillPortForwardDefaults(rule *PortForward, instDir string, param map[string
890936 }
891937 }
892938 if rule .GuestSocket != "" {
893- if out , err := executeGuestTemplate (rule .GuestSocket , instDir , param ); err == nil {
939+ if out , err := executeGuestTemplate (rule .GuestSocket , instDir , user , param ); err == nil {
894940 rule .GuestSocket = out .String ()
895941 } else {
896942 logrus .WithError (err ).Warnf ("Couldn't process guestSocket %q as a template" , rule .GuestSocket )
@@ -908,9 +954,9 @@ func FillPortForwardDefaults(rule *PortForward, instDir string, param map[string
908954 }
909955}
910956
911- func FillCopyToHostDefaults (rule * CopyToHost , instDir string , param map [string ]string ) {
957+ func FillCopyToHostDefaults (rule * CopyToHost , instDir string , user User , param map [string ]string ) {
912958 if rule .GuestFile != "" {
913- if out , err := executeGuestTemplate (rule .GuestFile , instDir , param ); err == nil {
959+ if out , err := executeGuestTemplate (rule .GuestFile , instDir , user , param ); err == nil {
914960 rule .GuestFile = out .String ()
915961 } else {
916962 logrus .WithError (err ).Warnf ("Couldn't process guest %q as a template" , rule .GuestFile )
0 commit comments