diff --git a/.codespellrc b/.codespellrc index 141e76106de..c3f69b585f5 100644 --- a/.codespellrc +++ b/.codespellrc @@ -6,7 +6,7 @@ skip = .git,*.pb.desc,*/node_modules/*,*/public/js/*,*/public/scss/* # Comma separated list of words to be ignored. Words must be lowercased. -ignore-words-list = ans,distroname,testof,hda,ststr +ignore-words-list = ans,distroname,testof,hda,ststr,archtypes # Check file names as well. check-filenames = true diff --git a/.gitignore b/.gitignore index 344e50b3d6b..086c11c818a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ _output/ _artifacts/ lima.REJECTED.yaml +schema-limayaml.json .config diff --git a/Makefile b/Makefile index 4ba40c18ac5..8f819545044 100644 --- a/Makefile +++ b/Makefile @@ -421,6 +421,14 @@ ifeq ($(native_compiling),true) --output _output --prefix $(PREFIX) endif +################################################################################ +schema-limayaml.json: _output/bin/limactl$(exe) + $< generate-jsonschema >$@ + +.PHONY: check-jsonschema +check-jsonschema: schema-limayaml.json + check-jsonschema --schemafile $< examples/default.yaml + ################################################################################ .PHONY: diagrams diagrams: docs/lima-sequence-diagram.png diff --git a/cmd/limactl/genschema.go b/cmd/limactl/genschema.go new file mode 100644 index 00000000000..687fb5e2df8 --- /dev/null +++ b/cmd/limactl/genschema.go @@ -0,0 +1,59 @@ +package main + +import ( + "encoding/json" + "fmt" + + "github.com/invopop/jsonschema" + "github.com/lima-vm/lima/pkg/limayaml" + "github.com/spf13/cobra" + orderedmap "github.com/wk8/go-ordered-map/v2" +) + +func newGenSchemaCommand() *cobra.Command { + genschemaCommand := &cobra.Command{ + Use: "generate-jsonschema", + Short: "Generate json-schema document", + Args: WrapArgsError(cobra.NoArgs), + RunE: genschemaAction, + Hidden: true, + } + return genschemaCommand +} + +func toAny(args []string) []any { + result := []any{nil} + for _, arg := range args { + result = append(result, arg) + } + return result +} + +func getProp(props *orderedmap.OrderedMap[string, *jsonschema.Schema], key string) *jsonschema.Schema { + value, ok := props.Get(key) + if !ok { + return nil + } + return value +} + +func genschemaAction(cmd *cobra.Command, _ []string) error { + schema := jsonschema.Reflect(&limayaml.LimaYAML{}) + // allow Disk to be either string (name) or object (struct) + schema.Definitions["Disk"].Type = "" // was: "object" + schema.Definitions["Disk"].OneOf = []*jsonschema.Schema{ + {Type: "string"}, + {Type: "object"}, + } + properties := schema.Definitions["LimaYAML"].Properties + getProp(properties, "os").Enum = toAny(limayaml.OSTypes) + getProp(properties, "arch").Enum = toAny(limayaml.ArchTypes) + getProp(properties, "mountType").Enum = toAny(limayaml.MountTypes) + getProp(properties, "vmType").Enum = toAny(limayaml.VMTypes) + j, err := json.MarshalIndent(schema, "", " ") + if err != nil { + return err + } + _, err = fmt.Fprintln(cmd.OutOrStdout(), string(j)) + return err +} diff --git a/cmd/limactl/main.go b/cmd/limactl/main.go index d069fbe82dc..24967b12bba 100644 --- a/cmd/limactl/main.go +++ b/cmd/limactl/main.go @@ -150,6 +150,7 @@ func newApp() *cobra.Command { newDiskCommand(), newUsernetCommand(), newGenDocCommand(), + newGenSchemaCommand(), newSnapshotCommand(), newProtectCommand(), newUnprotectCommand(), diff --git a/examples/default.yaml b/examples/default.yaml index 3d7d35dfe1c..802ab5f9d9d 100644 --- a/examples/default.yaml +++ b/examples/default.yaml @@ -32,7 +32,7 @@ os: null arch: null # OpenStack-compatible disk image. -# 🟢 Builtin default: null (must be specified) +# 🟢 Builtin default: none (must be specified) # 🔵 This file: Ubuntu images images: # Try to use release-yyyyMMdd image if available. Note that release-yyyyMMdd will be removed after several months. @@ -74,7 +74,7 @@ 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) +# 🟢 Builtin default: [] (Mount nothing) # 🔵 This file: Mount the home as read-only, /tmp/lima as writable mounts: - location: "~" @@ -123,8 +123,9 @@ mounts: # List of mount types not supported by the kernel of this distro. # Also used to resolve the default mount type when not explicitly specified. -# 🟢 Builtin default: null -mountTypesUnsupported: null +# 🟢 Builtin default: [] +mountTypesUnsupported: +# - "9p" # Mount type for above mounts, such as "reverse-sshfs" (from sshocker), "9p" (QEMU’s virtio-9p-pci, aka virtfs), # or "virtiofs" (experimental on Linux; needs `vmType: vz` on macOS). @@ -139,7 +140,7 @@ mountInotify: null # instance, labeled by name. (e.g. if the disk is named "data", it will be labeled # "lima-data" inside the instance). The disk will be mounted inside the instance at # `/mnt/lima-${VOLUME}`. -# 🟢 Builtin default: null +# 🟢 Builtin default: [] additionalDisks: # disks should either be a list of disk name strings, for example: # - "data" @@ -222,7 +223,7 @@ containerd: # Provisioning scripts need to be idempotent because they might be called # multiple times, e.g. when the host VM is being restarted. # The scripts can use the following template variables: {{.Home}}, {{.UID}}, {{.User}}, and {{.Param.Key}} -# 🟢 Builtin default: null +# 🟢 Builtin default: [] # provision: # # `system` is executed with root privileges # - mode: system @@ -265,7 +266,7 @@ containerd: # Probe scripts to check readiness. # The scripts run in user mode. They must start with a '#!' line. # The scripts can use the following template variables: {{.Home}}, {{.UID}}, {{.User}}, and {{.Param.Key}} -# 🟢 Builtin default: null +# 🟢 Builtin default: [] # probes: # # Only `readiness` probes are supported right now. # - mode: readiness @@ -352,7 +353,7 @@ video: # The instance can get routable IP addresses from the vmnet framework using # https://github.com/lima-vm/socket_vmnet. -# 🟢 Builtin default: null +# 🟢 Builtin default: [] networks: # Lima can manage daemons for networks defined in $LIMA_HOME/_config/networks.yaml # automatically. The socket_vmnet binary must be installed into @@ -435,7 +436,7 @@ networks: # The same template variables as for listing instances can be used, for example {{.Dir}}. # You can view the complete list of variables using `limactl list --list-fields` command. # It also includes {{.HostOS}} and {{.HostArch}} vars, for the runtime GOOS and GOARCH. -# 🟢 Builtin default: null +# 🟢 Builtin default: "" # message: | # This will be shown to the user. @@ -444,7 +445,7 @@ networks: # to /etc/environment. # If you set any of "ftp_proxy", "http_proxy", "https_proxy", or "no_proxy", then # Lima will automatically set an uppercase variant to the same value as well. -# 🟢 Builtin default: null +# 🟢 Builtin default: {} # env: # KEY: value @@ -480,7 +481,7 @@ hostResolver: # Static names can be defined here as an alternative to adding them to the hosts /etc/hosts. # Values can be either other hostnames, or IP addresses. The host.lima.internal name is # predefined to specify the gateway address to the host. - # 🟢 Builtin default: null + # 🟢 Builtin default: {} hosts: # guest.name: 127.1.1.1 # host.name: host.lima.internal @@ -492,7 +493,7 @@ hostResolver: # that has an IPv4 address, to the list. In case this still doesn't work (e.g. VPN # setups), the servers can be specified here explicitly. If nameservers are specified # here, then the configuration from network preferences will be ignored. -# 🟢 Builtin default: null +# 🟢 Builtin default: [] # dns: # - 1.1.1.1 # - 1.0.0.1 diff --git a/go.mod b/go.mod index b543014d2dc..3088f95086b 100644 --- a/go.mod +++ b/go.mod @@ -24,6 +24,7 @@ require ( github.com/goccy/go-yaml v1.12.0 github.com/google/go-cmp v0.6.0 github.com/google/yamlfmt v0.13.0 + github.com/invopop/jsonschema v0.12.0 github.com/lima-vm/go-qcow2reader v0.2.0 github.com/lima-vm/sshocker v0.3.4 github.com/mattn/go-isatty v0.0.20 @@ -39,6 +40,7 @@ require ( github.com/sirupsen/logrus v1.9.4-0.20230606125235-dd1b4c2e81af github.com/spf13/cobra v1.8.1 github.com/spf13/pflag v1.0.5 + github.com/wk8/go-ordered-map/v2 v2.1.8 golang.org/x/net v0.30.0 golang.org/x/sync v0.8.0 golang.org/x/sys v0.26.0 @@ -57,8 +59,10 @@ require ( github.com/VividCortex/ewma v1.2.0 // indirect github.com/a8m/envsubst v1.4.2 // indirect github.com/alecthomas/participle/v2 v2.1.1 // indirect + github.com/bahlo/generic-list-go v0.2.0 // indirect github.com/bmatcuk/doublestar/v4 v4.6.0 // indirect github.com/braydonk/yaml v0.7.0 // indirect + github.com/buger/jsonparser v1.1.1 // indirect github.com/containerd/errdefs v0.3.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/digitalocean/go-libvirt v0.0.0-20220804181439-8648fbde413e // indirect diff --git a/go.sum b/go.sum index e73d47ec8c0..0540b1b2b88 100644 --- a/go.sum +++ b/go.sum @@ -21,12 +21,16 @@ github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW5 github.com/apparentlymart/go-cidr v1.1.0 h1:2mAhrMoF+nhXqxTzSZMUzDHkLjmIHC+Zzn4tdgBZjnU= github.com/apparentlymart/go-cidr v1.1.0/go.mod h1:EBcsNrHc3zQeuaeCeCtQruQm+n9/YjEn/vI25Lg7Gwc= github.com/armon/go-proxyproto v0.0.0-20210323213023-7e956b284f0a/go.mod h1:QmP9hvJ91BbJmGVGSbutW19IC0Q9phDCLGaomwTJbgU= +github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk= +github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg= github.com/balajiv113/fd v0.0.0-20230330094840-143eec500f3e h1:IdMhFPEfTZQU971tIHx3UhY4l+yCeynprnINrDTSrOc= github.com/balajiv113/fd v0.0.0-20230330094840-143eec500f3e/go.mod h1:aXGMJsd3XrnUFTuyf/pTGg5jG6CY8JMZ5juywvShjgQ= github.com/bmatcuk/doublestar/v4 v4.6.0 h1:HTuxyug8GyFbRkrffIpzNCSK4luc0TY3wzXvzIZhEXc= github.com/bmatcuk/doublestar/v4 v4.6.0/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc= github.com/braydonk/yaml v0.7.0 h1:ySkqO7r0MGoCNhiRJqE0Xe9yhINMyvOAB3nFjgyJn2k= github.com/braydonk/yaml v0.7.0/go.mod h1:hcm3h581tudlirk8XEUPDBAimBPbmnL0Y45hCRl47N4= +github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs= +github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= github.com/cheggaaa/pb/v3 v3.1.5 h1:QuuUzeM2WsAqG2gMqtzaWithDJv0i+i6UlnwSCI4QLk= github.com/cheggaaa/pb/v3 v3.1.5/go.mod h1:CrxkeghYTXi1lQBEI7jSn+3svI3cuc19haAj6jM60XI= github.com/containerd/containerd v1.7.23 h1:H2CClyUkmpKAGlhQp95g2WXHfLYc7whAuvZGBNYOOwQ= @@ -140,6 +144,8 @@ github.com/inetaf/tcpproxy v0.0.0-20240214030015-3ce58045626c h1:gYfYE403/nlrGNY github.com/inetaf/tcpproxy v0.0.0-20240214030015-3ce58045626c/go.mod h1:Di7LXRyUcnvAcLicFhtM9/MlZl/TNgRSDHORM2c6CMI= github.com/insomniacslk/dhcp v0.0.0-20240710054256-ddd8a41251c9 h1:LZJWucZz7ztCqY6Jsu7N9g124iJ2kt/O62j3+UchZFg= github.com/insomniacslk/dhcp v0.0.0-20240710054256-ddd8a41251c9/go.mod h1:KclMyHxX06VrVr0DJmeFSUb1ankt7xTfoOA35pCkoic= +github.com/invopop/jsonschema v0.12.0 h1:6ovsNSuvn9wEQVOyc72aycBMVQFKz7cPdMJn10CvzRI= +github.com/invopop/jsonschema v0.12.0/go.mod h1:ffZ5Km5SWWRAIN6wbDXItl95euhFz2uON45H2qjYt+0= github.com/jinzhu/copier v0.4.0 h1:w3ciUoD19shMCRargcpm0cm91ytaBhDvuRpz1ODO/U8= github.com/jinzhu/copier v0.4.0/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= @@ -272,6 +278,8 @@ github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701 h1:pyC9PaHYZFgEKFdlp3G8 github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701/go.mod h1:P3a5rG4X7tI17Nn3aOIAYr5HbIMukwXG0urG0WuL8OA= github.com/ulikunitz/xz v0.5.11 h1:kpFauv27b6ynzBNT/Xy+1k+fK4WswhN/6PN5WhFAGw8= github.com/ulikunitz/xz v0.5.11/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= +github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc= +github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= diff --git a/pkg/cidata/cidata.go b/pkg/cidata/cidata.go index 722c1a6c947..a35fccf77b2 100644 --- a/pkg/cidata/cidata.go +++ b/pkg/cidata/cidata.go @@ -202,7 +202,7 @@ func templateArgs(bootScripts bool, instDir, name string, instConfig *limayaml.L if err != nil { return nil, err } - mountPoint, err := localpathutil.Expand(f.MountPoint) + mountPoint, err := localpathutil.Expand(*f.MountPoint) if err != nil { return nil, err } diff --git a/pkg/hostagent/mount.go b/pkg/hostagent/mount.go index fda4fff261f..646dc5d4eb3 100644 --- a/pkg/hostagent/mount.go +++ b/pkg/hostagent/mount.go @@ -37,7 +37,7 @@ func (a *HostAgent) setupMount(m limayaml.Mount) (*mount, error) { return nil, err } - mountPoint, err := localpathutil.Expand(m.MountPoint) + mountPoint, err := localpathutil.Expand(*m.MountPoint) if err != nil { return nil, err } diff --git a/pkg/limayaml/defaults.go b/pkg/limayaml/defaults.go index 32817cee55c..40ff36711e8 100644 --- a/pkg/limayaml/defaults.go +++ b/pkg/limayaml/defaults.go @@ -619,10 +619,12 @@ func FillDefault(y, d, o *LimaYAML, filePath 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 mount.MountPoint != nil { + if out, err := executeGuestTemplate(*mount.MountPoint, instDir, y.Param); err == nil { + mount.MountPoint = ptr.Of(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 { @@ -652,7 +654,7 @@ func FillDefault(y, d, o *LimaYAML, filePath string) { if mount.Writable != nil { mounts[i].Writable = mount.Writable } - if mount.MountPoint != "" { + if mount.MountPoint != nil { mounts[i].MountPoint = mount.MountPoint } } else { @@ -695,8 +697,8 @@ func FillDefault(y, d, o *LimaYAML, filePath string) { mounts[i].NineP.Cache = ptr.Of(Default9pCacheForRO) } } - if mount.MountPoint == "" { - mounts[i].MountPoint = mount.Location + if mount.MountPoint == nil { + mounts[i].MountPoint = ptr.Of(mount.Location) } } diff --git a/pkg/limayaml/defaults_test.go b/pkg/limayaml/defaults_test.go index f65d4594ec7..848dc8036ef 100644 --- a/pkg/limayaml/defaults_test.go +++ b/pkg/limayaml/defaults_test.go @@ -132,7 +132,7 @@ func TestFillDefault(t *testing.T) { }, Mounts: []Mount{ {Location: "/tmp"}, - {Location: "{{.Dir}}/{{.Param.ONE}}", MountPoint: "/mnt/{{.Param.ONE}}"}, + {Location: "{{.Dir}}/{{.Param.ONE}}", MountPoint: ptr.Of("/mnt/{{.Param.ONE}}")}, }, MountType: ptr.Of(NINEP), Provision: []Provision{ @@ -205,7 +205,7 @@ func TestFillDefault(t *testing.T) { } expect.Mounts = slices.Clone(y.Mounts) - expect.Mounts[0].MountPoint = expect.Mounts[0].Location + expect.Mounts[0].MountPoint = ptr.Of(expect.Mounts[0].Location) expect.Mounts[0].Writable = ptr.Of(false) expect.Mounts[0].SSHFS.Cache = ptr.Of(true) expect.Mounts[0].SSHFS.FollowSymlinks = ptr.Of(false) @@ -217,7 +217,7 @@ func TestFillDefault(t *testing.T) { 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].MountPoint = ptr.Of(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) @@ -431,7 +431,7 @@ func TestFillDefault(t *testing.T) { expect.Containerd.Archives = slices.Clone(d.Containerd.Archives) expect.Containerd.Archives[0].Arch = *d.Arch expect.Mounts = slices.Clone(d.Mounts) - expect.Mounts[0].MountPoint = expect.Mounts[0].Location + expect.Mounts[0].MountPoint = ptr.Of(expect.Mounts[0].Location) expect.Mounts[0].SSHFS.Cache = ptr.Of(true) expect.Mounts[0].SSHFS.FollowSymlinks = ptr.Of(false) expect.Mounts[0].SSHFS.SFTPDriver = ptr.Of("") diff --git a/pkg/limayaml/limayaml.go b/pkg/limayaml/limayaml.go index 469cb7a3033..dc27723e512 100644 --- a/pkg/limayaml/limayaml.go +++ b/pkg/limayaml/limayaml.go @@ -7,46 +7,46 @@ import ( ) type LimaYAML struct { - MinimumLimaVersion *string `yaml:"minimumLimaVersion,omitempty" json:"minimumLimaVersion,omitempty"` - VMType *VMType `yaml:"vmType,omitempty" json:"vmType,omitempty"` + MinimumLimaVersion *string `yaml:"minimumLimaVersion,omitempty" json:"minimumLimaVersion,omitempty" jsonschema:"nullable"` + VMType *VMType `yaml:"vmType,omitempty" json:"vmType,omitempty" jsonschema:"nullable"` VMOpts VMOpts `yaml:"vmOpts,omitempty" json:"vmOpts,omitempty"` - OS *OS `yaml:"os,omitempty" json:"os,omitempty"` - Arch *Arch `yaml:"arch,omitempty" json:"arch,omitempty"` + OS *OS `yaml:"os,omitempty" json:"os,omitempty" jsonschema:"nullable"` + Arch *Arch `yaml:"arch,omitempty" json:"arch,omitempty" jsonschema:"nullable"` Images []Image `yaml:"images" json:"images"` // REQUIRED - CPUType CPUType `yaml:"cpuType,omitempty" json:"cpuType,omitempty"` - CPUs *int `yaml:"cpus,omitempty" json:"cpus,omitempty"` - Memory *string `yaml:"memory,omitempty" json:"memory,omitempty"` // go-units.RAMInBytes - Disk *string `yaml:"disk,omitempty" json:"disk,omitempty"` // go-units.RAMInBytes - AdditionalDisks []Disk `yaml:"additionalDisks,omitempty" json:"additionalDisks,omitempty"` + CPUType CPUType `yaml:"cpuType,omitempty" json:"cpuType,omitempty" jsonschema:"nullable"` + CPUs *int `yaml:"cpus,omitempty" json:"cpus,omitempty" jsonschema:"nullable"` + Memory *string `yaml:"memory,omitempty" json:"memory,omitempty" jsonschema:"nullable"` // go-units.RAMInBytes + Disk *string `yaml:"disk,omitempty" json:"disk,omitempty" jsonschema:"nullable"` // go-units.RAMInBytes + AdditionalDisks []Disk `yaml:"additionalDisks,omitempty" json:"additionalDisks,omitempty" jsonschema:"nullable"` Mounts []Mount `yaml:"mounts,omitempty" json:"mounts,omitempty"` - MountTypesUnsupported []string `yaml:"mountTypesUnsupported,omitempty" json:"mountTypesUnsupported,omitempty"` - MountType *MountType `yaml:"mountType,omitempty" json:"mountType,omitempty"` - MountInotify *bool `yaml:"mountInotify,omitempty" json:"mountInotify,omitempty"` + MountTypesUnsupported []string `yaml:"mountTypesUnsupported,omitempty" json:"mountTypesUnsupported,omitempty" jsonschema:"nullable"` + MountType *MountType `yaml:"mountType,omitempty" json:"mountType,omitempty" jsonschema:"nullable"` + MountInotify *bool `yaml:"mountInotify,omitempty" json:"mountInotify,omitempty" jsonschema:"nullable"` SSH SSH `yaml:"ssh,omitempty" json:"ssh,omitempty"` // REQUIRED (FIXME) Firmware Firmware `yaml:"firmware,omitempty" json:"firmware,omitempty"` Audio Audio `yaml:"audio,omitempty" json:"audio,omitempty"` Video Video `yaml:"video,omitempty" json:"video,omitempty"` Provision []Provision `yaml:"provision,omitempty" json:"provision,omitempty"` - UpgradePackages *bool `yaml:"upgradePackages,omitempty" json:"upgradePackages,omitempty"` + UpgradePackages *bool `yaml:"upgradePackages,omitempty" json:"upgradePackages,omitempty" jsonschema:"nullable"` Containerd Containerd `yaml:"containerd,omitempty" json:"containerd,omitempty"` - GuestInstallPrefix *string `yaml:"guestInstallPrefix,omitempty" json:"guestInstallPrefix,omitempty"` + GuestInstallPrefix *string `yaml:"guestInstallPrefix,omitempty" json:"guestInstallPrefix,omitempty" jsonschema:"nullable"` Probes []Probe `yaml:"probes,omitempty" json:"probes,omitempty"` PortForwards []PortForward `yaml:"portForwards,omitempty" json:"portForwards,omitempty"` CopyToHost []CopyToHost `yaml:"copyToHost,omitempty" json:"copyToHost,omitempty"` Message string `yaml:"message,omitempty" json:"message,omitempty"` - Networks []Network `yaml:"networks,omitempty" json:"networks,omitempty"` + Networks []Network `yaml:"networks,omitempty" json:"networks,omitempty" jsonschema:"nullable"` // `network` was deprecated in Lima v0.7.0, removed in Lima v0.14.0. Use `networks` instead. Env map[string]string `yaml:"env,omitempty" json:"env,omitempty"` Param map[string]string `yaml:"param,omitempty" json:"param,omitempty"` DNS []net.IP `yaml:"dns,omitempty" json:"dns,omitempty"` HostResolver HostResolver `yaml:"hostResolver,omitempty" json:"hostResolver,omitempty"` // `useHostResolver` was deprecated in Lima v0.8.1, removed in Lima v0.14.0. Use `hostResolver.enabled` instead. - PropagateProxyEnv *bool `yaml:"propagateProxyEnv,omitempty" json:"propagateProxyEnv,omitempty"` + PropagateProxyEnv *bool `yaml:"propagateProxyEnv,omitempty" json:"propagateProxyEnv,omitempty" jsonschema:"nullable"` CACertificates CACertificates `yaml:"caCerts,omitempty" json:"caCerts,omitempty"` Rosetta Rosetta `yaml:"rosetta,omitempty" json:"rosetta,omitempty"` - Plain *bool `yaml:"plain,omitempty" json:"plain,omitempty"` - TimeZone *string `yaml:"timezone,omitempty" json:"timezone,omitempty"` - NestedVirtualization *bool `yaml:"nestedVirtualization,omitempty" json:"nestedVirtualization,omitempty"` + Plain *bool `yaml:"plain,omitempty" json:"plain,omitempty" jsonschema:"nullable"` + TimeZone *string `yaml:"timezone,omitempty" json:"timezone,omitempty" jsonschema:"nullable"` + NestedVirtualization *bool `yaml:"nestedVirtualization,omitempty" json:"nestedVirtualization,omitempty" jsonschema:"nullable"` } type ( @@ -76,17 +76,24 @@ const ( WSL2 VMType = "wsl2" ) +var ( + OSTypes = []OS{LINUX} + ArchTypes = []Arch{X8664, AARCH64, ARMV7L, RISCV64} + MountTypes = []MountType{REVSSHFS, NINEP, VIRTIOFS, WSLMount} + VMTypes = []VMType{QEMU, VZ, WSL2} +) + type VMOpts struct { QEMU QEMUOpts `yaml:"qemu,omitempty" json:"qemu,omitempty"` } type QEMUOpts struct { - MinimumVersion *string `yaml:"minimumVersion,omitempty" json:"minimumVersion,omitempty"` + MinimumVersion *string `yaml:"minimumVersion,omitempty" json:"minimumVersion,omitempty" jsonschema:"nullable"` } type Rosetta struct { - Enabled *bool `yaml:"enabled,omitempty" json:"enabled,omitempty"` - BinFmt *bool `yaml:"binfmt,omitempty" json:"binfmt,omitempty"` + Enabled *bool `yaml:"enabled,omitempty" json:"enabled,omitempty" jsonschema:"nullable"` + BinFmt *bool `yaml:"binfmt,omitempty" json:"binfmt,omitempty" jsonschema:"nullable"` } type File struct { @@ -120,8 +127,8 @@ type Disk struct { type Mount struct { Location string `yaml:"location" json:"location"` // REQUIRED - MountPoint string `yaml:"mountPoint,omitempty" json:"mountPoint,omitempty"` - Writable *bool `yaml:"writable,omitempty" json:"writable,omitempty"` + MountPoint *string `yaml:"mountPoint,omitempty" json:"mountPoint,omitempty" jsonschema:"nullable"` + Writable *bool `yaml:"writable,omitempty" json:"writable,omitempty" jsonschema:"nullable"` SSHFS SSHFS `yaml:"sshfs,omitempty" json:"sshfs,omitempty"` NineP NineP `yaml:"9p,omitempty" json:"9p,omitempty"` Virtiofs Virtiofs `yaml:"virtiofs,omitempty" json:"virtiofs,omitempty"` @@ -135,16 +142,16 @@ const ( ) type SSHFS struct { - Cache *bool `yaml:"cache,omitempty" json:"cache,omitempty"` - FollowSymlinks *bool `yaml:"followSymlinks,omitempty" json:"followSymlinks,omitempty"` - SFTPDriver *SFTPDriver `yaml:"sftpDriver,omitempty" json:"sftpDriver,omitempty"` + Cache *bool `yaml:"cache,omitempty" json:"cache,omitempty" jsonschema:"nullable"` + FollowSymlinks *bool `yaml:"followSymlinks,omitempty" json:"followSymlinks,omitempty" jsonschema:"nullable"` + SFTPDriver *SFTPDriver `yaml:"sftpDriver,omitempty" json:"sftpDriver,omitempty" jsonschema:"nullable"` } type NineP struct { - SecurityModel *string `yaml:"securityModel,omitempty" json:"securityModel,omitempty"` - ProtocolVersion *string `yaml:"protocolVersion,omitempty" json:"protocolVersion,omitempty"` - Msize *string `yaml:"msize,omitempty" json:"msize,omitempty"` - Cache *string `yaml:"cache,omitempty" json:"cache,omitempty"` + SecurityModel *string `yaml:"securityModel,omitempty" json:"securityModel,omitempty" jsonschema:"nullable"` + ProtocolVersion *string `yaml:"protocolVersion,omitempty" json:"protocolVersion,omitempty" jsonschema:"nullable"` + Msize *string `yaml:"msize,omitempty" json:"msize,omitempty" jsonschema:"nullable"` + Cache *string `yaml:"cache,omitempty" json:"cache,omitempty" jsonschema:"nullable"` } type Virtiofs struct { @@ -152,19 +159,19 @@ type Virtiofs struct { } type SSH struct { - LocalPort *int `yaml:"localPort,omitempty" json:"localPort,omitempty"` + LocalPort *int `yaml:"localPort,omitempty" json:"localPort,omitempty" jsonschema:"nullable"` // LoadDotSSHPubKeys loads ~/.ssh/*.pub in addition to $LIMA_HOME/_config/user.pub . - LoadDotSSHPubKeys *bool `yaml:"loadDotSSHPubKeys,omitempty" json:"loadDotSSHPubKeys,omitempty"` // default: false - ForwardAgent *bool `yaml:"forwardAgent,omitempty" json:"forwardAgent,omitempty"` // default: false - ForwardX11 *bool `yaml:"forwardX11,omitempty" json:"forwardX11,omitempty"` // default: false - ForwardX11Trusted *bool `yaml:"forwardX11Trusted,omitempty" json:"forwardX11Trusted,omitempty"` // default: false + LoadDotSSHPubKeys *bool `yaml:"loadDotSSHPubKeys,omitempty" json:"loadDotSSHPubKeys,omitempty" jsonschema:"nullable"` // default: false + ForwardAgent *bool `yaml:"forwardAgent,omitempty" json:"forwardAgent,omitempty" jsonschema:"nullable"` // default: false + ForwardX11 *bool `yaml:"forwardX11,omitempty" json:"forwardX11,omitempty" jsonschema:"nullable"` // default: false + ForwardX11Trusted *bool `yaml:"forwardX11Trusted,omitempty" json:"forwardX11Trusted,omitempty" jsonschema:"nullable"` // default: false } type Firmware struct { // LegacyBIOS disables UEFI if set. // LegacyBIOS is ignored for aarch64. - LegacyBIOS *bool `yaml:"legacyBIOS,omitempty" json:"legacyBIOS,omitempty"` + LegacyBIOS *bool `yaml:"legacyBIOS,omitempty" json:"legacyBIOS,omitempty" jsonschema:"nullable"` // Images specify UEFI images (edk2-aarch64-code.fd.gz). // Defaults to built-in UEFI. @@ -173,17 +180,17 @@ type Firmware struct { type Audio struct { // Device is a QEMU audiodev string - Device *string `yaml:"device,omitempty" json:"device,omitempty"` + Device *string `yaml:"device,omitempty" json:"device,omitempty" jsonschema:"nullable"` } type VNCOptions struct { - Display *string `yaml:"display,omitempty" json:"display,omitempty"` + Display *string `yaml:"display,omitempty" json:"display,omitempty" jsonschema:"nullable"` } type Video struct { // Display is a QEMU display string - Display *string `yaml:"display,omitempty" json:"display,omitempty"` - VNC VNCOptions `yaml:"vnc" json:"vnc"` + Display *string `yaml:"display,omitempty" json:"display,omitempty" jsonschema:"nullable"` + VNC VNCOptions `yaml:"vnc,omitempty" json:"vnc,omitempty"` } type ProvisionMode = string @@ -197,16 +204,16 @@ const ( ) type Provision struct { - Mode ProvisionMode `yaml:"mode" json:"mode"` // default: "system" + Mode ProvisionMode `yaml:"mode,omitempty" json:"mode,omitempty" jsonschema:"default=system"` SkipDefaultDependencyResolution *bool `yaml:"skipDefaultDependencyResolution,omitempty" json:"skipDefaultDependencyResolution,omitempty"` Script string `yaml:"script" json:"script"` Playbook string `yaml:"playbook,omitempty" json:"playbook,omitempty"` } type Containerd struct { - System *bool `yaml:"system,omitempty" json:"system,omitempty"` // default: false - User *bool `yaml:"user,omitempty" json:"user,omitempty"` // default: true - Archives []File `yaml:"archives,omitempty" json:"archives,omitempty"` // default: see defaultContainerdArchives + System *bool `yaml:"system,omitempty" json:"system,omitempty" jsonschema:"nullable"` // default: false + User *bool `yaml:"user,omitempty" json:"user,omitempty" jsonschema:"nullable"` // default: true + Archives []File `yaml:"archives,omitempty" json:"archives,omitempty"` // default: see defaultContainerdArchives } type ProbeMode = string @@ -216,10 +223,10 @@ const ( ) type Probe struct { - Mode ProbeMode // default: "readiness" - Description string - Script string - Hint string + Mode ProbeMode `yaml:"mode,omitempty" json:"mode,omitempty" jsonschema:"default=readiness"` + Description string `yaml:"description,omitempty" json:"description,omitempty"` + Script string `yaml:"script,omitempty" json:"script,omitempty"` + Hint string `yaml:"hint,omitempty" json:"hint,omitempty"` } type Proto = string @@ -264,13 +271,13 @@ type Network struct { } type HostResolver struct { - Enabled *bool `yaml:"enabled,omitempty" json:"enabled,omitempty"` - IPv6 *bool `yaml:"ipv6,omitempty" json:"ipv6,omitempty"` - Hosts map[string]string `yaml:"hosts,omitempty" json:"hosts,omitempty"` + Enabled *bool `yaml:"enabled,omitempty" json:"enabled,omitempty" jsonschema:"nullable"` + IPv6 *bool `yaml:"ipv6,omitempty" json:"ipv6,omitempty" jsonschema:"nullable"` + Hosts map[string]string `yaml:"hosts,omitempty" json:"hosts,omitempty" jsonschema:"nullable"` } type CACertificates struct { - RemoveDefaults *bool `yaml:"removeDefaults,omitempty" json:"removeDefaults,omitempty"` // default: false - Files []string `yaml:"files,omitempty" json:"files,omitempty"` - Certs []string `yaml:"certs,omitempty" json:"certs,omitempty"` + RemoveDefaults *bool `yaml:"removeDefaults,omitempty" json:"removeDefaults,omitempty" jsonschema:"nullable"` // default: false + Files []string `yaml:"files,omitempty" json:"files,omitempty" jsonschema:"nullable"` + Certs []string `yaml:"certs,omitempty" json:"certs,omitempty" jsonschema:"nullable"` } diff --git a/pkg/limayaml/validate.go b/pkg/limayaml/validate.go index 123f9b85432..6c1a5d6d658 100644 --- a/pkg/limayaml/validate.go +++ b/pkg/limayaml/validate.go @@ -487,7 +487,7 @@ func ValidateParamIsUsed(y *LimaYAML) error { keyIsUsed = true break } - if re.MatchString(p.MountPoint) { + if p.MountPoint != nil && re.MatchString(*p.MountPoint) { keyIsUsed = true break }