Skip to content

Commit

Permalink
Merge pull request #2306 from afbjorklund/schema
Browse files Browse the repository at this point in the history
Add command to generate jsonschema for limayaml
  • Loading branch information
AkihiroSuda authored Oct 19, 2024
2 parents 7da2a20 + 55224aa commit bc7788b
Show file tree
Hide file tree
Showing 14 changed files with 173 additions and 82 deletions.
2 changes: 1 addition & 1 deletion .codespellrc
Original file line number Diff line number Diff line change
Expand Up @@ -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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
_output/
_artifacts/
lima.REJECTED.yaml
schema-limayaml.json
.config
8 changes: 8 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
59 changes: 59 additions & 0 deletions cmd/limactl/genschema.go
Original file line number Diff line number Diff line change
@@ -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
}
1 change: 1 addition & 0 deletions cmd/limactl/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ func newApp() *cobra.Command {
newDiskCommand(),
newUsernetCommand(),
newGenDocCommand(),
newGenSchemaCommand(),
newSnapshotCommand(),
newProtectCommand(),
newUnprotectCommand(),
Expand Down
25 changes: 13 additions & 12 deletions examples/default.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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: "~"
Expand Down Expand Up @@ -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).
Expand All @@ -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"
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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.

Expand All @@ -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

Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down
4 changes: 4 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand Down
8 changes: 8 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,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=
Expand Down Expand Up @@ -142,6 +146,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=
Expand Down Expand Up @@ -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=
Expand Down
2 changes: 1 addition & 1 deletion pkg/cidata/cidata.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/hostagent/mount.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
16 changes: 9 additions & 7 deletions pkg/limayaml/defaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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)
}
}

Expand Down
8 changes: 4 additions & 4 deletions pkg/limayaml/defaults_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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{
Expand Down Expand Up @@ -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)
Expand All @@ -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)
Expand Down Expand Up @@ -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("")
Expand Down
Loading

0 comments on commit bc7788b

Please sign in to comment.