Repository: lima-vm/lima
Pull request #2667 (2024-09-29 01:06:49)

Refactor: network.YAML → network.Config
Because YAML is just the serialization format, and not what the data is used for.


Patch:
diff --git a/cmd/limactl/sudoers.go b/cmd/limactl/sudoers.go
index 9645e47d..9b54adfc 100644
--- a/cmd/limactl/sudoers.go
+++ b/cmd/limactl/sudoers.go
@@ -36,9 +36,9 @@ See %s for the usage.`, networksMD),
 		RunE:    sudoersAction,
 		GroupID: advancedCommand,
 	}
-	configFile, _ := networks.ConfigFile()
+	cfgFile, _ := networks.ConfigFile()
 	sudoersCommand.Flags().Bool("check", false,
-		fmt.Sprintf("check that the sudoers file is up-to-date with %q", configFile))
+		fmt.Sprintf("check that the sudoers file is up-to-date with %q", cfgFile))
 	return sudoersCommand
 }
 
@@ -46,12 +46,12 @@ func sudoersAction(cmd *cobra.Command, args []string) error {
 	if runtime.GOOS != "darwin" {
 		return errors.New("sudoers command is only supported on macOS right now")
 	}
-	config, err := networks.Config()
+	nwCfg, err := networks.LoadConfig()
 	if err != nil {
 		return err
 	}
 	// Make sure the current network configuration is secure
-	if err := config.Validate(); err != nil {
+	if err := nwCfg.Validate(); err != nil {
 		return err
 	}
 	check, err := cmd.Flags().GetBool("check")
@@ -59,7 +59,7 @@ func sudoersAction(cmd *cobra.Command, args []string) error {
 		return err
 	}
 	if check {
-		return verifySudoAccess(config, args)
+		return verifySudoAccess(nwCfg, args)
 	}
 	switch len(args) {
 	case 0:
@@ -77,21 +77,21 @@ func sudoersAction(cmd *cobra.Command, args []string) error {
 	return nil
 }
 
-func verifySudoAccess(config networks.YAML, args []string) error {
+func verifySudoAccess(nwCfg networks.Config, args []string) error {
 	var file string
 	switch len(args) {
 	case 0:
-		file = config.Paths.Sudoers
+		file = nwCfg.Paths.Sudoers
 		if file == "" {
-			configFile, _ := networks.ConfigFile()
-			return fmt.Errorf("no sudoers file defined in %q", configFile)
+			cfgFile, _ := networks.ConfigFile()
+			return fmt.Errorf("no sudoers file defined in %q", cfgFile)
 		}
 	case 1:
 		file = args[0]
 	default:
 		return errors.New("can check only a single sudoers file")
 	}
-	if err := config.VerifySudoAccess(file); err != nil {
+	if err := nwCfg.VerifySudoAccess(file); err != nil {
 		return err
 	}
 	fmt.Printf("%q is up-to-date (or sudo doesn't require a password)\n", file)
diff --git a/pkg/limayaml/validate.go b/pkg/limayaml/validate.go
index a647f146..f8113f8a 100644
--- a/pkg/limayaml/validate.go
+++ b/pkg/limayaml/validate.go
@@ -364,14 +364,14 @@ func validateNetwork(y *LimaYAML) error {
 		field := fmt.Sprintf("networks[%d]", i)
 		switch {
 		case nw.Lima != "":
-			config, err := networks.Config()
+			nwCfg, err := networks.LoadConfig()
 			if err != nil {
 				return err
 			}
-			if config.Check(nw.Lima) != nil {
+			if nwCfg.Check(nw.Lima) != nil {
 				return fmt.Errorf("field `%s.lima` references network %q which is not defined in networks.yaml", field, nw.Lima)
 			}
-			usernet, err := config.Usernet(nw.Lima)
+			usernet, err := nwCfg.Usernet(nw.Lima)
 			if err != nil {
 				return err
 			}
diff --git a/pkg/networks/commands.go b/pkg/networks/commands.go
index 8ddfff75..8003812d 100644
--- a/pkg/networks/commands.go
+++ b/pkg/networks/commands.go
@@ -16,36 +16,36 @@ const (
 )
 
 // Commands in `sudoers` cannot use quotes, so all arguments are printed via "%s"
-// and not "%q". config.Paths.* entries must not include any whitespace!
+// and not "%q". cfg.Paths.* entries must not include any whitespace!
 
-func (config *YAML) Check(name string) error {
-	if _, ok := config.Networks[name]; ok {
+func (c *Config) Check(name string) error {
+	if _, ok := c.Networks[name]; ok {
 		return nil
 	}
 	return fmt.Errorf("network %q is not defined", name)
 }
 
 // Usernet returns true if the mode of given network is ModeUserV2.
-func (config *YAML) Usernet(name string) (bool, error) {
-	if nw, ok := config.Networks[name]; ok {
+func (c *Config) Usernet(name string) (bool, error) {
+	if nw, ok := c.Networks[name]; ok {
 		return nw.Mode == ModeUserV2, nil
 	}
 	return false, fmt.Errorf("network %q is not defined", name)
 }
 
 // DaemonPath returns the daemon path.
-func (config *YAML) DaemonPath(daemon string) (string, error) {
+func (c *Config) DaemonPath(daemon string) (string, error) {
 	switch daemon {
 	case SocketVMNet:
-		return config.Paths.SocketVMNet, nil
+		return c.Paths.SocketVMNet, nil
 	default:
 		return "", fmt.Errorf("unknown daemon type %q", daemon)
 	}
 }
 
 // IsDaemonInstalled checks whether the daemon is installed.
-func (config *YAML) IsDaemonInstalled(daemon string) (bool, error) {
-	p, err := config.DaemonPath(daemon)
+func (c *Config) IsDaemonInstalled(daemon string) (bool, error) {
+	p, err := c.DaemonPath(daemon)
 	if err != nil {
 		return false, err
 	}
@@ -62,22 +62,22 @@ func (config *YAML) IsDaemonInstalled(daemon string) (bool, error) {
 }
 
 // Sock returns a socket_vmnet socket.
-func (config *YAML) Sock(name string) string {
-	return filepath.Join(config.Paths.VarRun, fmt.Sprintf("socket_vmnet.%s", name))
+func (c *Config) Sock(name string) string {
+	return filepath.Join(c.Paths.VarRun, fmt.Sprintf("socket_vmnet.%s", name))
 }
 
-func (config *YAML) PIDFile(name, daemon string) string {
-	return filepath.Join(config.Paths.VarRun, fmt.Sprintf("%s_%s.pid", name, daemon))
+func (c *Config) PIDFile(name, daemon string) string {
+	return filepath.Join(c.Paths.VarRun, fmt.Sprintf("%s_%s.pid", name, daemon))
 }
 
-func (config *YAML) LogFile(name, daemon, stream string) string {
+func (c *Config) LogFile(name, daemon, stream string) string {
 	networksDir, _ := dirnames.LimaNetworksDir()
 	return filepath.Join(networksDir, fmt.Sprintf("%s_%s.%s.log", name, daemon, stream))
 }
 
-func (config *YAML) User(daemon string) (osutil.User, error) {
-	if ok, _ := config.IsDaemonInstalled(daemon); !ok {
-		daemonPath, _ := config.DaemonPath(daemon)
+func (c *Config) User(daemon string) (osutil.User, error) {
+	if ok, _ := c.IsDaemonInstalled(daemon); !ok {
+		daemonPath, _ := c.DaemonPath(daemon)
 		return osutil.User{}, fmt.Errorf("daemon %q (path=%q) is not available", daemon, daemonPath)
 	}
 	//nolint:gocritic // singleCaseSwitch: should rewrite switch statement to if statement
@@ -88,23 +88,23 @@ func (config *YAML) User(daemon string) (osutil.User, error) {
 	return osutil.User{}, fmt.Errorf("daemon %q not defined", daemon)
 }
 
-func (config *YAML) MkdirCmd() string {
-	return fmt.Sprintf("/bin/mkdir -m 775 -p %s", config.Paths.VarRun)
+func (c *Config) MkdirCmd() string {
+	return fmt.Sprintf("/bin/mkdir -m 775 -p %s", c.Paths.VarRun)
 }
 
-func (config *YAML) StartCmd(name, daemon string) string {
-	if ok, _ := config.IsDaemonInstalled(daemon); !ok {
+func (c *Config) StartCmd(name, daemon string) string {
+	if ok, _ := c.IsDaemonInstalled(daemon); !ok {
 		panic(fmt.Errorf("daemon %q is not available", daemon))
 	}
 	var cmd string
 	switch daemon {
 	case SocketVMNet:
-		nw := config.Networks[name]
-		if config.Paths.SocketVMNet == "" {
-			panic("config.Paths.SocketVMNet is empty")
+		nw := c.Networks[name]
+		if c.Paths.SocketVMNet == "" {
+			panic("c.Paths.SocketVMNet is empty")
 		}
 		cmd = fmt.Sprintf("%s --pidfile=%s --socket-group=%s --vmnet-mode=%s",
-			config.Paths.SocketVMNet, config.PIDFile(name, SocketVMNet), config.Group, nw.Mode)
+			c.Paths.SocketVMNet, c.PIDFile(name, SocketVMNet), c.Group, nw.Mode)
 		switch nw.Mode {
 		case ModeBridged:
 			cmd += fmt.Sprintf(" --vmnet-interface=%s", nw.Interface)
@@ -112,13 +112,13 @@ func (config *YAML) StartCmd(name, daemon string) string {
 			cmd += fmt.Sprintf(" --vmnet-gateway=%s --vmnet-dhcp-end=%s --vmnet-mask=%s",
 				nw.Gateway, nw.DHCPEnd, nw.NetMask)
 		}
-		cmd += " " + config.Sock(name)
+		cmd += " " + c.Sock(name)
 	default:
 		panic(fmt.Errorf("unexpected daemon %q", daemon))
 	}
 	return cmd
 }
 
-func (config *YAML) StopCmd(name, daemon string) string {
-	return fmt.Sprintf("/usr/bin/pkill -F %s", config.PIDFile(name, daemon))
+func (c *Config) StopCmd(name, daemon string) string {
+	return fmt.Sprintf("/usr/bin/pkill -F %s", c.PIDFile(name, daemon))
 }
diff --git a/pkg/networks/config.go b/pkg/networks/config.go
index 65ec62fa..c051111e 100644
--- a/pkg/networks/config.go
+++ b/pkg/networks/config.go
@@ -51,109 +51,109 @@ func defaultConfigBytes() ([]byte, error) {
 	return textutil.ExecuteTemplate(defaultConfigTemplate, args)
 }
 
-func fillDefaults(nwYaml YAML) (YAML, error) {
+func fillDefaults(cfg Config) (Config, error) {
 	usernetFound := false
-	if nwYaml.Networks == nil {
-		nwYaml.Networks = make(map[string]Network)
+	if cfg.Networks == nil {
+		cfg.Networks = make(map[string]Network)
 	}
-	for nw := range nwYaml.Networks {
-		if nwYaml.Networks[nw].Mode == ModeUserV2 && nwYaml.Networks[nw].Gateway != nil {
+	for nw := range cfg.Networks {
+		if cfg.Networks[nw].Mode == ModeUserV2 && cfg.Networks[nw].Gateway != nil {
 			usernetFound = true
 		}
 	}
 	if !usernetFound {
-		defaultConfig, err := DefaultConfig()
+		defaultCfg, err := DefaultConfig()
 		if err != nil {
-			return nwYaml, err
+			return cfg, err
 		}
-		nwYaml.Networks[ModeUserV2] = defaultConfig.Networks[ModeUserV2]
+		cfg.Networks[ModeUserV2] = defaultCfg.Networks[ModeUserV2]
 	}
-	return nwYaml, nil
+	return cfg, nil
 }
 
-func DefaultConfig() (YAML, error) {
-	var config YAML
-	defaultConfig, err := defaultConfigBytes()
+func DefaultConfig() (Config, error) {
+	var cfg Config
+	b, err := defaultConfigBytes()
 	if err != nil {
-		return config, err
+		return cfg, err
 	}
-	err = yaml.UnmarshalWithOptions(defaultConfig, &config, yaml.Strict())
+	err = yaml.UnmarshalWithOptions(b, &cfg, yaml.Strict())
 	if err != nil {
-		return config, err
+		return cfg, err
 	}
-	return config, nil
+	return cfg, nil
 }
 
 var cache struct {
 	sync.Once
-	config YAML
-	err    error
+	cfg Config
+	err error
 }
 
 func ConfigFile() (string, error) {
-	configDir, err := dirnames.LimaConfigDir()
+	cfgDir, err := dirnames.LimaConfigDir()
 	if err != nil {
 		return "", err
 	}
-	return filepath.Join(configDir, filenames.NetworksConfig), nil
+	return filepath.Join(cfgDir, filenames.NetworksConfig), nil
 }
 
 // loadCache loads the _config/networks.yaml file into the cache.
 func loadCache() {
 	cache.Do(func() {
-		var configFile string
-		configFile, cache.err = ConfigFile()
+		var cfgFile string
+		cfgFile, cache.err = ConfigFile()
 		if cache.err != nil {
 			return
 		}
-		_, cache.err = os.Stat(configFile)
+		_, cache.err = os.Stat(cfgFile)
 		if cache.err != nil {
 			if !errors.Is(cache.err, os.ErrNotExist) {
 				return
 			}
-			configDir := filepath.Dir(configFile)
-			cache.err = os.MkdirAll(configDir, 0o755)
+			cfgDir := filepath.Dir(cfgFile)
+			cache.err = os.MkdirAll(cfgDir, 0o755)
 			if cache.err != nil {
-				cache.err = fmt.Errorf("could not create %q directory: %w", configDir, cache.err)
+				cache.err = fmt.Errorf("could not create %q directory: %w", cfgDir, cache.err)
 				return
 			}
-			var defaultConfig []byte
-			defaultConfig, cache.err = defaultConfigBytes()
+			var b []byte
+			b, cache.err = defaultConfigBytes()
 			if cache.err != nil {
 				return
 			}
-			cache.err = os.WriteFile(configFile, defaultConfig, 0o644)
+			cache.err = os.WriteFile(cfgFile, b, 0o644)
 			if cache.err != nil {
 				return
 			}
 		}
 		var b []byte
-		b, cache.err = os.ReadFile(configFile)
+		b, cache.err = os.ReadFile(cfgFile)
 		if cache.err != nil {
 			return
 		}
-		cache.err = yaml.UnmarshalWithOptions(b, &cache.config, yaml.DisallowDuplicateKey())
+		cache.err = yaml.UnmarshalWithOptions(b, &cache.cfg, yaml.DisallowDuplicateKey())
 		if cache.err != nil {
-			cache.err = fmt.Errorf("cannot parse %q: %w", configFile, cache.err)
+			cache.err = fmt.Errorf("cannot parse %q: %w", cfgFile, cache.err)
 			return
 		}
-		var strictConfig YAML
-		if strictErr := yaml.UnmarshalWithOptions(b, &strictConfig, yaml.Strict()); strictErr != nil {
-			// Allow non-existing YAML fields, as a config created with Lima < v0.22 contains `vdeSwitch` and `vdeVMNet`.
+		var strictCfg Config
+		if strictErr := yaml.UnmarshalWithOptions(b, &strictCfg, yaml.Strict()); strictErr != nil {
+			// Allow non-existing YAML fields, as a cfg created with Lima < v0.22 contains `vdeSwitch` and `vdeVMNet`.
 			// These fields were removed in Lima v0.22.
-			logrus.WithError(strictErr).Warn("Non-strict YAML is deprecated and will be unsupported in a future version of Lima: " + configFile)
+			logrus.WithError(strictErr).Warn("Non-strict YAML is deprecated and will be unsupported in a future version of Lima: " + cfgFile)
 		}
-		cache.config, cache.err = fillDefaults(cache.config)
+		cache.cfg, cache.err = fillDefaults(cache.cfg)
 		if cache.err != nil {
-			cache.err = fmt.Errorf("cannot fill default %q: %w", configFile, cache.err)
+			cache.err = fmt.Errorf("cannot fill default %q: %w", cfgFile, cache.err)
 		}
 	})
 }
 
-// Config returns the network config from the _config/networks.yaml file.
-func Config() (YAML, error) {
+// LoadConfig returns the network cfg from the _config/networks.yaml file.
+func LoadConfig() (Config, error) {
 	loadCache()
-	return cache.config, cache.err
+	return cache.cfg, cache.err
 }
 
 // Sock returns a socket_vmnet socket.
@@ -162,13 +162,13 @@ func Sock(name string) (string, error) {
 	if cache.err != nil {
 		return "", cache.err
 	}
-	if err := cache.config.Check(name); err != nil {
+	if err := cache.cfg.Check(name); err != nil {
 		return "", err
 	}
-	if cache.config.Paths.SocketVMNet == "" {
+	if cache.cfg.Paths.SocketVMNet == "" {
 		return "", errors.New("socketVMNet is not set")
 	}
-	return cache.config.Sock(name), nil
+	return cache.cfg.Sock(name), nil
 }
 
 // IsUsernet returns true if the given network name is a usernet network.
@@ -178,7 +178,7 @@ func IsUsernet(name string) bool {
 	if cache.err != nil {
 		return false
 	}
-	isUsernet, err := cache.config.Usernet(name)
+	isUsernet, err := cache.cfg.Usernet(name)
 	if err != nil {
 		return false
 	}
diff --git a/pkg/networks/networks.go b/pkg/networks/networks.go
index fc7bade0..cf2d376b 100644
--- a/pkg/networks/networks.go
+++ b/pkg/networks/networks.go
@@ -2,7 +2,7 @@ package networks
 
 import "net"
 
-type YAML struct {
+type Config struct {
 	Paths    Paths              `yaml:"paths"`
 	Group    string             `yaml:"group,omitempty"` // default: "everyone"
 	Networks map[string]Network `yaml:"networks"`
diff --git a/pkg/networks/reconcile/reconcile.go b/pkg/networks/reconcile/reconcile.go
index 918a07fa..c40ab4b3 100644
--- a/pkg/networks/reconcile/reconcile.go
+++ b/pkg/networks/reconcile/reconcile.go
@@ -20,7 +20,7 @@ import (
 )
 
 func Reconcile(ctx context.Context, newInst string) error {
-	config, err := networks.Config()
+	cfg, err := networks.LoadConfig()
 	if err != nil {
 		return err
 	}
@@ -42,19 +42,19 @@ func Reconcile(ctx context.Context, newInst string) error {
 			if nw.Lima == "" {
 				continue
 			}
-			if _, ok := config.Networks[nw.Lima]; !ok {
+			if _, ok := cfg.Networks[nw.Lima]; !ok {
 				logrus.Errorf("network %q (used by instance %q) is missing from networks.yaml", nw.Lima, instName)
 				continue
 			}
 			activeNetwork[nw.Lima] = true
 		}
 	}
-	for name := range config.Networks {
+	for name := range cfg.Networks {
 		var err error
 		if activeNetwork[name] {
-			err = startNetwork(ctx, &config, name)
+			err = startNetwork(ctx, &cfg, name)
 		} else {
-			err = stopNetwork(ctx, &config, name)
+			err = stopNetwork(ctx, &cfg, name)
 		}
 		if err != nil {
 			return err
@@ -78,8 +78,8 @@ func sudo(user, group, command string) error {
 	return nil
 }
 
-func makeVarRun(config *networks.YAML) error {
-	err := sudo("root", "wheel", config.MkdirCmd())
+func makeVarRun(cfg *networks.Config) error {
+	err := sudo("root", "wheel", cfg.MkdirCmd())
 	if err != nil {
 		return err
 	}
@@ -87,14 +87,14 @@ func makeVarRun(config *networks.YAML) error {
 	// Check that VarRun is daemon-group writable. If we don't report it here, the error would only be visible
 	// in the vde_switch daemon log. This has not been checked by networks.Validate() because only the VarRun
 	// directory itself needs to be daemon-group writable, any parents just need to be daemon-group executable.
-	fi, err := os.Stat(config.Paths.VarRun)
+	fi, err := os.Stat(cfg.Paths.VarRun)
 	if err != nil {
 		return err
 	}
 	stat, ok := osutil.SysStat(fi)
 	if !ok {
 		// should never happen
-		return fmt.Errorf("could not retrieve stat buffer for %q", config.Paths.VarRun)
+		return fmt.Errorf("could not retrieve stat buffer for %q", cfg.Paths.VarRun)
 	}
 	daemon, err := osutil.LookupUser("daemon")
 	if err != nil {
@@ -102,13 +102,13 @@ func makeVarRun(config *networks.YAML) error {
 	}
 	if fi.Mode()&0o20 == 0 || stat.Gid != daemon.Gid {
 		return fmt.Errorf("%q doesn't seem to be writable by the daemon (gid:%d) group",
-			config.Paths.VarRun, daemon.Gid)
+			cfg.Paths.VarRun, daemon.Gid)
 	}
 	return nil
 }
 
-func startDaemon(ctx context.Context, config *networks.YAML, name, daemon string) error {
-	if err := makeVarRun(config); err != nil {
+func startDaemon(ctx context.Context, cfg *networks.Config, name, daemon string) error {
+	if err := makeVarRun(cfg); err != nil {
 		return err
 	}
 	networksDir, err := dirnames.LimaNetworksDir()
@@ -118,20 +118,20 @@ func startDaemon(ctx context.Context, config *networks.YAML, name, daemon string
 	if err := os.MkdirAll(networksDir, 0o755); err != nil {
 		return err
 	}
-	user, err := config.User(daemon)
+	user, err := cfg.User(daemon)
 	if err != nil {
 		return err
 	}
 
 	args := []string{"--user", user.User, "--group", user.Group, "--non-interactive"}
-	args = append(args, strings.Split(config.StartCmd(name, daemon), " ")...)
+	args = append(args, strings.Split(cfg.StartCmd(name, daemon), " ")...)
 	cmd := exec.CommandContext(ctx, "sudo", args...)
 	// set directory to a path the daemon user has read access to because vde_switch calls getcwd() which
 	// can fail when called from directories like ~/Downloads, which has 700 permissions
-	cmd.Dir = config.Paths.VarRun
+	cmd.Dir = cfg.Paths.VarRun
 
-	stdoutPath := config.LogFile(name, daemon, "stdout")
-	stderrPath := config.LogFile(name, daemon, "stderr")
+	stdoutPath := cfg.LogFile(name, daemon, "stdout")
+	stderrPath := cfg.LogFile(name, daemon, "stderr")
 	if err := os.RemoveAll(stdoutPath); err != nil {
 		return err
 	}
@@ -160,22 +160,22 @@ var validation struct {
 	err error
 }
 
-func validateConfig(config *networks.YAML) error {
+func validateConfig(cfg *networks.Config) error {
 	validation.Do(func() {
-		// make sure all config.Paths.* are secure
-		validation.err = config.Validate()
+		// make sure all cfg.Paths.* are secure
+		validation.err = cfg.Validate()
 		if validation.err == nil {
-			validation.err = config.VerifySudoAccess(config.Paths.Sudoers)
+			validation.err = cfg.VerifySudoAccess(cfg.Paths.Sudoers)
 		}
 	})
 	return validation.err
 }
 
-func startNetwork(ctx context.Context, config *networks.YAML, name string) error {
+func startNetwork(ctx context.Context, cfg *networks.Config, name string) error {
 	logrus.Debugf("Make sure %q network is running", name)
 
 	// Handle usernet first without sudo requirements
-	isUsernet, err := config.Usernet(name)
+	isUsernet, err := cfg.Usernet(name)
 	if err != nil {
 		return err
 	}
@@ -190,11 +190,11 @@ func startNetwork(ctx context.Context, config *networks.YAML, name string) error
 		return nil
 	}
 
-	if err := validateConfig(config); err != nil {
+	if err := validateConfig(cfg); err != nil {
 		return err
 	}
 	var daemons []string
-	ok, err := config.IsDaemonInstalled(networks.SocketVMNet)
+	ok, err := cfg.IsDaemonInstalled(networks.SocketVMNet)
 	if err != nil {
 		return err
 	}
@@ -204,10 +204,10 @@ func startNetwork(ctx context.Context, config *networks.YAML, name string) error
 		return fmt.Errorf("daemon %q needs to be installed", networks.SocketVMNet)
 	}
 	for _, daemon := range daemons {
-		pid, _ := store.ReadPIDFile(config.PIDFile(name, daemon))
+		pid, _ := store.ReadPIDFile(cfg.PIDFile(name, daemon))
 		if pid == 0 {
 			logrus.Infof("Starting %s daemon for %q network", daemon, name)
-			if err := startDaemon(ctx, config, name, daemon); err != nil {
+			if err := startDaemon(ctx, cfg, name, daemon); err != nil {
 				return err
 			}
 		}
@@ -215,10 +215,10 @@ func startNetwork(ctx context.Context, config *networks.YAML, name string) error
 	return nil
 }
 
-func stopNetwork(ctx context.Context, config *networks.YAML, name string) error {
+func stopNetwork(ctx context.Context, cfg *networks.Config, name string) error {
 	logrus.Debugf("Make sure %q network is stopped", name)
 	// Handle usernet first without sudo requirements
-	isUsernet, err := config.Usernet(name)
+	isUsernet, err := cfg.Usernet(name)
 	if err != nil {
 		return err
 	}
@@ -236,20 +236,20 @@ func stopNetwork(ctx context.Context, config *networks.YAML, name string) error
 	// Don't call validateConfig() until we actually need to stop a daemon because
 	// stopNetwork() may be called even when the daemons are not installed.
 	for _, daemon := range []string{networks.SocketVMNet} {
-		if ok, _ := config.IsDaemonInstalled(daemon); !ok {
+		if ok, _ := cfg.IsDaemonInstalled(daemon); !ok {
 			continue
 		}
-		pid, _ := store.ReadPIDFile(config.PIDFile(name, daemon))
+		pid, _ := store.ReadPIDFile(cfg.PIDFile(name, daemon))
 		if pid != 0 {
 			logrus.Infof("Stopping %s daemon for %q network", daemon, name)
-			if err := validateConfig(config); err != nil {
+			if err := validateConfig(cfg); err != nil {
 				return err
 			}
-			user, err := config.User(daemon)
+			user, err := cfg.User(daemon)
 			if err != nil {
 				return err
 			}
-			err = sudo(user.User, user.Group, config.StopCmd(name, daemon))
+			err = sudo(user.User, user.Group, cfg.StopCmd(name, daemon))
 			if err != nil {
 				return err
 			}
@@ -258,7 +258,7 @@ func stopNetwork(ctx context.Context, config *networks.YAML, name string) error
 		// will cause subsequent start commands to fail.
 		startWaiting := time.Now()
 		for {
-			if pid, _ := store.ReadPIDFile(config.PIDFile(name, daemon)); pid == 0 {
+			if pid, _ := store.ReadPIDFile(cfg.PIDFile(name, daemon)); pid == 0 {
 				break
 			}
 			if time.Since(startWaiting) > 5*time.Second {
diff --git a/pkg/networks/sudoers.go b/pkg/networks/sudoers.go
index 0c95a509..08a45f59 100644
--- a/pkg/networks/sudoers.go
+++ b/pkg/networks/sudoers.go
@@ -12,17 +12,17 @@ import (
 )
 
 func Sudoers() (string, error) {
-	config, err := Config()
+	cfg, err := LoadConfig()
 	if err != nil {
 		return "", err
 	}
 
 	var sb strings.Builder
-	sb.WriteString(fmt.Sprintf("%%%s ALL=(root:wheel) NOPASSWD:NOSETENV: %s\n", config.Group, config.MkdirCmd()))
+	sb.WriteString(fmt.Sprintf("%%%s ALL=(root:wheel) NOPASSWD:NOSETENV: %s\n", cfg.Group, cfg.MkdirCmd()))
 
 	// names must be in stable order to be able to check if sudoers file needs updating
-	names := make([]string, 0, len(config.Networks))
-	for name, nw := range config.Networks {
+	names := make([]string, 0, len(cfg.Networks))
+	for name, nw := range cfg.Networks {
 		if nw.Mode == ModeUserV2 {
 			continue // no sudo needed
 		}
@@ -34,26 +34,26 @@ func Sudoers() (string, error) {
 		sb.WriteRune('\n')
 		sb.WriteString(fmt.Sprintf("# Manage %q network daemons\n", name))
 		for _, daemon := range []string{SocketVMNet} {
-			if ok, err := config.IsDaemonInstalled(daemon); err != nil {
+			if ok, err := cfg.IsDaemonInstalled(daemon); err != nil {
 				return "", err
 			} else if !ok {
 				continue
 			}
-			user, err := config.User(daemon)
+			user, err := cfg.User(daemon)
 			if err != nil {
 				return "", err
 			}
 			sb.WriteRune('\n')
 			sb.WriteString(fmt.Sprintf("%%%s ALL=(%s:%s) NOPASSWD:NOSETENV: \\\n",
-				config.Group, user.User, user.Group))
-			sb.WriteString(fmt.Sprintf("    %s, \\\n", config.StartCmd(name, daemon)))
-			sb.WriteString(fmt.Sprintf("    %s\n", config.StopCmd(name, daemon)))
+				cfg.Group, user.User, user.Group))
+			sb.WriteString(fmt.Sprintf("    %s, \\\n", cfg.StartCmd(name, daemon)))
+			sb.WriteString(fmt.Sprintf("    %s\n", cfg.StopCmd(name, daemon)))
 		}
 	}
 	return sb.String(), nil
 }
 
-func (config *YAML) passwordLessSudo() error {
+func (c *Config) passwordLessSudo() error {
 	// Flush cached sudo password
 	cmd := exec.Command("sudo", "-k")
 	if err := cmd.Run(); err != nil {
@@ -62,12 +62,12 @@ func (config *YAML) passwordLessSudo() error {
 	// Verify that user/groups for both daemons work without a password, e.g.
 	// %admin ALL = (ALL:ALL) NOPASSWD: ALL
 	for _, daemon := range []string{SocketVMNet} {
-		if ok, err := config.IsDaemonInstalled(daemon); err != nil {
+		if ok, err := c.IsDaemonInstalled(daemon); err != nil {
 			return err
 		} else if !ok {
 			continue
 		}
-		user, err := config.User(daemon)
+		user, err := c.User(daemon)
 		if err != nil {
 			return err
 		}
@@ -79,9 +79,9 @@ func (config *YAML) passwordLessSudo() error {
 	return nil
 }
 
-func (config *YAML) VerifySudoAccess(sudoersFile string) error {
+func (c *Config) VerifySudoAccess(sudoersFile string) error {
 	if sudoersFile == "" {
-		err := config.passwordLessSudo()
+		err := c.passwordLessSudo()
 		if err == nil {
 			logrus.Debug("sudo doesn't seem to require a password")
 			return nil
@@ -95,7 +95,7 @@ func (config *YAML) VerifySudoAccess(sudoersFile string) error {
 		// Default networks.yaml specifies /etc/sudoers.d/lima file. Don't throw an error when the
 		// file doesn't exist, as long as password-less sudo still works.
 		if errors.Is(err, os.ErrNotExist) {
-			err = config.passwordLessSudo()
+			err = c.passwordLessSudo()
 			if err == nil {
 				logrus.Debugf("%q does not exist, but sudo doesn't seem to require a password", sudoersFile)
 				return nil
diff --git a/pkg/networks/usernet/config.go b/pkg/networks/usernet/config.go
index ae798044..ec0f0d84 100644
--- a/pkg/networks/usernet/config.go
+++ b/pkg/networks/usernet/config.go
@@ -52,15 +52,15 @@ func PIDFile(name string) (string, error) {
 
 // SubnetCIDR returns a subnet in form of net.IPNet for the given network name.
 func SubnetCIDR(name string) (*net.IPNet, error) {
-	config, err := networks.Config()
+	cfg, err := networks.LoadConfig()
 	if err != nil {
 		return nil, err
 	}
-	err = config.Check(name)
+	err = cfg.Check(name)
 	if err != nil {
 		return nil, err
 	}
-	_, ipNet, err := netmaskToCidr(config.Networks[name].Gateway, config.Networks[name].NetMask)
+	_, ipNet, err := netmaskToCidr(cfg.Networks[name].Gateway, cfg.Networks[name].NetMask)
 	if err != nil {
 		return nil, err
 	}
@@ -69,15 +69,15 @@ func SubnetCIDR(name string) (*net.IPNet, error) {
 
 // Subnet returns a subnet net.IP for the given network name.
 func Subnet(name string) (net.IP, error) {
-	config, err := networks.Config()
+	cfg, err := networks.LoadConfig()
 	if err != nil {
 		return nil, err
 	}
-	err = config.Check(name)
+	err = cfg.Check(name)
 	if err != nil {
 		return nil, err
 	}
-	_, ipNet, err := netmaskToCidr(config.Networks[name].Gateway, config.Networks[name].NetMask)
+	_, ipNet, err := netmaskToCidr(cfg.Networks[name].Gateway, cfg.Networks[name].NetMask)
 	if err != nil {
 		return nil, err
 	}
diff --git a/pkg/networks/validate.go b/pkg/networks/validate.go
index 9aa6c0e0..6c2c1a49 100644
--- a/pkg/networks/validate.go
+++ b/pkg/networks/validate.go
@@ -15,9 +15,9 @@ import (
 	"github.com/lima-vm/lima/pkg/osutil"
 )
 
-func (config *YAML) Validate() error {
+func (c *Config) Validate() error {
 	// validate all paths.* values
-	paths := reflect.ValueOf(&config.Paths).Elem()
+	paths := reflect.ValueOf(&c.Paths).Elem()
 	pathsMap := make(map[string]string, paths.NumField())
 	var socketVMNetNotFound bool
 	for i := 0; i < paths.NumField(); i++ {
diff --git a/pkg/qemu/qemu.go b/pkg/qemu/qemu.go
index e090cdc3..10ab28c5 100644
--- a/pkg/qemu/qemu.go
+++ b/pkg/qemu/qemu.go
@@ -726,7 +726,7 @@ func Cmdline(ctx context.Context, cfg Config) (exe string, args []string, err er
 
 	for i, nw := range y.Networks {
 		if nw.Lima != "" {
-			nwCfg, err := networks.Config()
+			nwCfg, err := networks.LoadConfig()
 			if err != nil {
 				return "", nil, err
 			}
@@ -956,48 +956,48 @@ func FindVirtiofsd(qemuExe string) (string, error) {
 		candidates = append(candidates, filepath.Join("/usr", relativePath))
 	}
 
-	for _, vhostConfigsDir := range candidates {
-		logrus.Debugf("Checking vhost directory %s", vhostConfigsDir)
+	for _, vhostCfgsDir := range candidates {
+		logrus.Debugf("Checking vhost directory %s", vhostCfgsDir)
 
-		configEntries, err := os.ReadDir(vhostConfigsDir)
+		cfgEntries, err := os.ReadDir(vhostCfgsDir)
 		if err != nil {
 			logrus.Debugf("Failed to list vhost directory: %v", err)
 			continue
 		}
 
-		for _, configEntry := range configEntries {
-			logrus.Debugf("Checking vhost config %s", configEntry.Name())
-			if !strings.HasSuffix(configEntry.Name(), ".json") {
+		for _, cfgEntry := range cfgEntries {
+			logrus.Debugf("Checking vhost vhostCfg %s", cfgEntry.Name())
+			if !strings.HasSuffix(cfgEntry.Name(), ".json") {
 				continue
 			}
 
-			var config vhostUserBackend
-			contents, err := os.ReadFile(filepath.Join(vhostConfigsDir, configEntry.Name()))
+			var vhostCfg vhostUserBackend
+			contents, err := os.ReadFile(filepath.Join(vhostCfgsDir, cfgEntry.Name()))
 			if err == nil {
-				err = json.Unmarshal(contents, &config)
+				err = json.Unmarshal(contents, &vhostCfg)
 			}
 
 			if err != nil {
-				logrus.Warnf("Failed to load vhost-user config %s: %v", configEntry.Name(), err)
+				logrus.Warnf("Failed to load vhost-user config %s: %v", cfgEntry.Name(), err)
 				continue
 			}
-			logrus.Debugf("%v", config)
+			logrus.Debugf("%v", vhostCfg)
 
-			if config.BackendType != "fs" {
+			if vhostCfg.BackendType != "fs" {
 				continue
 			}
 
 			// Only rust virtiofsd supports --version, so use that to make sure this isn't
 			// QEMU's virtiofsd, which requires running as root.
-			cmd := exec.Command(config.Binary, "--version")
+			cmd := exec.Command(vhostCfg.Binary, "--version")
 			output, err := cmd.CombinedOutput()
 			if err != nil {
 				logrus.Warnf("Failed to run %s --version (is this QEMU virtiofsd?): %s: %s",
-					config.Binary, err, output)
+					vhostCfg.Binary, err, output)
 				continue
 			}
 
-			return config.Binary, nil
+			return vhostCfg.Binary, nil
 		}
 	}
 
diff --git a/pkg/vz/vm_darwin.go b/pkg/vz/vm_darwin.go
index 1ad7b3f7..56faeec9 100644
--- a/pkg/vz/vm_darwin.go
+++ b/pkg/vz/vm_darwin.go
@@ -324,7 +324,7 @@ func attachNetwork(driver *driver.BaseDriver, vmConfig *vz.VirtualMachineConfigu
 			}
 			configurations = append(configurations, networkConfig)
 		} else if nw.Lima != "" {
-			nwCfg, err := networks.Config()
+			nwCfg, err := networks.LoadConfig()
 			if err != nil {
 				return err
 			}


Test patch:
diff --git a/pkg/networks/config_test.go b/pkg/networks/config_test.go
index 7af5a36a..e8057429 100644
--- a/pkg/networks/config_test.go
+++ b/pkg/networks/config_test.go
@@ -8,11 +8,10 @@ import (
 )
 
 func TestFillDefault(t *testing.T) {
-	nwYaml := YAML{}
-	newYaml, err := fillDefaults(nwYaml)
+	cfg, err := fillDefaults(Config{})
 	assert.NilError(t, err)
 
-	userNet := newYaml.Networks[ModeUserV2]
+	userNet := cfg.Networks[ModeUserV2]
 	assert.Equal(t, userNet.Mode, ModeUserV2)
 	assert.Equal(t, userNet.Interface, "")
 	assert.DeepEqual(t, userNet.NetMask, net.ParseIP("255.255.255.0"))
@@ -21,13 +20,13 @@ func TestFillDefault(t *testing.T) {
 }
 
 func TestFillDefaultWithV2(t *testing.T) {
-	nwYaml := YAML{Networks: map[string]Network{
+	cfg := Config{Networks: map[string]Network{
 		"user-v2": {Mode: ModeUserV2},
 	}}
-	newYaml, err := fillDefaults(nwYaml)
+	cfg, err := fillDefaults(cfg)
 	assert.NilError(t, err)
 
-	userNet := newYaml.Networks[ModeUserV2]
+	userNet := cfg.Networks[ModeUserV2]
 	assert.Equal(t, userNet.Mode, ModeUserV2)
 	assert.Equal(t, userNet.Interface, "")
 	assert.DeepEqual(t, userNet.NetMask, net.ParseIP("255.255.255.0"))
@@ -36,13 +35,13 @@ func TestFillDefaultWithV2(t *testing.T) {
 }
 
 func TestFillDefaultWithV2AndGateway(t *testing.T) {
-	nwYaml := YAML{Networks: map[string]Network{
+	cfg := Config{Networks: map[string]Network{
 		"user-v2": {Mode: ModeUserV2, Gateway: net.ParseIP("192.168.105.1")},
 	}}
-	newYaml, err := fillDefaults(nwYaml)
+	cfg, err := fillDefaults(cfg)
 	assert.NilError(t, err)
 
-	userNet := newYaml.Networks[ModeUserV2]
+	userNet := cfg.Networks[ModeUserV2]
 	assert.Equal(t, userNet.Mode, ModeUserV2)
 	assert.Equal(t, userNet.Interface, "")
 	assert.DeepEqual(t, userNet.NetMask, net.IP{})