From aa35fe408bc72aa48bf89c7dcb60cf23ec6fb03a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anders=20F=20Bj=C3=B6rklund?= Date: Thu, 2 May 2024 17:57:23 +0200 Subject: [PATCH] Run cloud-config schema validation on-demand MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Anders F Björklund --- cmd/limactl/validate.go | 59 ++++++++++++++++++++++++++++++++++++--- pkg/cidata/schema.go | 7 +---- pkg/cidata/schema_test.go | 2 +- pkg/cidata/template.go | 5 ---- 4 files changed, 57 insertions(+), 16 deletions(-) diff --git a/cmd/limactl/validate.go b/cmd/limactl/validate.go index 9561903e57d..748deb21694 100644 --- a/cmd/limactl/validate.go +++ b/cmd/limactl/validate.go @@ -1,9 +1,13 @@ package main import ( + "bufio" + "io" "fmt" + "os" "github.com/lima-vm/lima/cmd/limactl/guessarg" + "github.com/lima-vm/lima/pkg/cidata" "github.com/lima-vm/lima/pkg/store" "github.com/spf13/cobra" @@ -21,15 +25,62 @@ func newValidateCommand() *cobra.Command { return validateCommand } +func firstLine(f string) (string, error) { + file, err := os.Open(f) + if err != nil { + return "", err + } + defer file.Close() + scanner := bufio.NewScanner(file) + scanner.Scan() + if err := scanner.Err(); err != nil { + return "", err + } + return scanner.Text(), nil +} + +func validateCloudConfig(f string) error { + file, err := os.Open(f) + if err != nil { + return fmt.Errorf("failed to load YAML file %q: %w", f, err) + } + defer file.Close() + b, err := io.ReadAll(file) + if err != nil { + return err + } + if err = cidata.ValidateCloudConfig(b); err != nil { + return err + } + return nil +} + +func validateLimayaml(f string) error { + _, err := store.LoadYAMLByFilePath(f) + if err != nil { + return fmt.Errorf("failed to load YAML file %q: %w", f, err) + } + if _, err := guessarg.InstNameFromYAMLPath(f); err != nil { + return err + } + return nil +} + func validateAction(_ *cobra.Command, args []string) error { for _, f := range args { - _, err := store.LoadYAMLByFilePath(f) + line, err := firstLine(f) if err != nil { - return fmt.Errorf("failed to load YAML file %q: %w", f, err) - } - if _, err := guessarg.InstNameFromYAMLPath(f); err != nil { return err } + if line == "#cloud-config" { + if err := validateCloudConfig(f); err != nil { + return err + } + } else { + if err := validateLimayaml(f); err != nil { + return err + } + } logrus.Infof("%q: OK", f) } diff --git a/pkg/cidata/schema.go b/pkg/cidata/schema.go index 43066310a5c..27045248bf5 100644 --- a/pkg/cidata/schema.go +++ b/pkg/cidata/schema.go @@ -1,9 +1,7 @@ package cidata import ( - "bytes" _ "embed" - "fmt" "strings" "github.com/santhosh-tekuri/jsonschema/v5" @@ -16,10 +14,7 @@ const schemaURL = "https://raw.githubusercontent.com/canonical/cloud-init/main/c //go:embed schemas/schema-cloud-config-v1.json var schemaText string -func validateCloudConfig(userData []byte) error { - if !bytes.HasPrefix(userData, []byte("#cloud-config")) { - return fmt.Errorf("missing #cloud-config") - } +func ValidateCloudConfig(userData []byte) error { var m interface{} err := yaml.Unmarshal(userData, &m) if err != nil { diff --git a/pkg/cidata/schema_test.go b/pkg/cidata/schema_test.go index 73144c4e04b..999c92495fd 100644 --- a/pkg/cidata/schema_test.go +++ b/pkg/cidata/schema_test.go @@ -11,6 +11,6 @@ func TestValidate(t *testing.T) { users: - default ` - err := validateCloudConfig([]byte(config)) + err := ValidateCloudConfig([]byte(config)) assert.NilError(t, err) } diff --git a/pkg/cidata/template.go b/pkg/cidata/template.go index 54ec2bbaab3..b9aa9618820 100644 --- a/pkg/cidata/template.go +++ b/pkg/cidata/template.go @@ -147,11 +147,6 @@ func ExecuteTemplate(args TemplateArgs) ([]iso9660util.Entry, error) { if err != nil { return err } - if d.Name() == "user-data" { - if err := validateCloudConfig(b); err != nil { - return err - } - } layout = append(layout, iso9660util.Entry{ Path: path, Reader: bytes.NewReader(b),