diff --git a/cmd/cli/kubectl-kyverno/create/command.go b/cmd/cli/kubectl-kyverno/create/command.go new file mode 100644 index 0000000000..b6e83df095 --- /dev/null +++ b/cmd/cli/kubectl-kyverno/create/command.go @@ -0,0 +1,18 @@ +package create + +import ( + "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/create/test" + "github.com/spf13/cobra" +) + +func Command() *cobra.Command { + cmd := &cobra.Command{ + Use: "create", + Example: "", + RunE: func(cmd *cobra.Command, args []string) error { + return cmd.Help() + }, + } + cmd.AddCommand(test.Command()) + return cmd +} diff --git a/cmd/cli/kubectl-kyverno/create/templates/templates.go b/cmd/cli/kubectl-kyverno/create/templates/templates.go new file mode 100644 index 0000000000..af38c1a343 --- /dev/null +++ b/cmd/cli/kubectl-kyverno/create/templates/templates.go @@ -0,0 +1,8 @@ +package templates + +import ( + _ "embed" +) + +//go:embed test.yaml +var TestTemplate string diff --git a/cmd/cli/kubectl-kyverno/create/templates/test.yaml b/cmd/cli/kubectl-kyverno/create/templates/test.yaml new file mode 100644 index 0000000000..52d824cc48 --- /dev/null +++ b/cmd/cli/kubectl-kyverno/create/templates/test.yaml @@ -0,0 +1,28 @@ +# test name +name: {{ .Name }} + +# list of policy files +policies: +{{- range .Policies }} + - {{ . }} +{{- end }} + +# list of resource files +resources: +{{- range .Resources }} + - {{ . }} +{{- end }} + +# variables file (optional) +variables: {{ .Values }} + +# list of expected results +results: +{{- range .Results }} + - policy: {{ .Policy }} + rule: {{ .Rule }} + resource: {{ .Resource }} + namespace: {{ .Namespace }} + kind: {{ .Kind }} + result: {{ .Result }} +{{- end }} diff --git a/cmd/cli/kubectl-kyverno/create/test/command.go b/cmd/cli/kubectl-kyverno/create/test/command.go new file mode 100644 index 0000000000..b74275283e --- /dev/null +++ b/cmd/cli/kubectl-kyverno/create/test/command.go @@ -0,0 +1,107 @@ +package test + +import ( + "os" + "strings" + "text/template" + + "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/create/templates" + "github.com/spf13/cobra" +) + +type result struct { + Policy string + Rule string + Resource string + Namespace string + Kind string + PatchedResource string + Result string +} + +type options struct { + Name string + Policies []string + Resources []string + Values string + Results []*result +} + +func Command() *cobra.Command { + var path string + var options options + var pass, fail, skip []string + cmd := &cobra.Command{ + Use: "test", + Short: "Create a Kyverno test file.", + Example: "kyverno create test -p policy.yaml -r resource.yaml -f values.yaml --pass policy-name,rule-name,resource-name,resource-namespace,resource-kind", + RunE: func(cmd *cobra.Command, args []string) error { + tmpl, err := template.New("test").Parse(templates.TestTemplate) + if err != nil { + return err + } + for _, result := range pass { + result := parseResult(result, "pass") + if result != nil { + options.Results = append(options.Results, result) + } + } + for _, result := range fail { + result := parseResult(result, "fail") + if result != nil { + options.Results = append(options.Results, result) + } + } + for _, result := range skip { + result := parseResult(result, "skip") + if result != nil { + options.Results = append(options.Results, result) + } + } + output := os.Stdout + if path != "" { + file, err := os.Create(path) + if err != nil { + return err + } + defer file.Close() + output = file + } + return tmpl.Execute(output, options) + }, + } + cmd.Flags().StringVarP(&path, "output", "o", "", "Output path (uses standard console output if not set)") + cmd.Flags().StringVarP(&options.Name, "name", "n", "test-name", "Test name") + cmd.Flags().StringSliceVarP(&options.Policies, "policy", "p", nil, "List of policy files") + cmd.Flags().StringSliceVarP(&options.Resources, "resource", "r", nil, "List of resource files") + cmd.Flags().StringVarP(&options.Values, "values", "f", "", "Values file") + cmd.Flags().StringArrayVar(&pass, "pass", nil, "Expected `pass` results") + cmd.Flags().StringArrayVar(&fail, "fail", nil, "Expected `fail` results") + cmd.Flags().StringArrayVar(&skip, "skip", nil, "Expected `skip` results") + return cmd +} + +func parseResult(test string, status string) *result { + parts := strings.Split(test, ",") + if len(parts) == 5 { + return &result{ + Policy: parts[0], + Rule: parts[1], + Resource: parts[2], + Namespace: parts[3], + Kind: parts[4], + Result: status, + } + } else if len(parts) == 6 { + return &result{ + Policy: parts[0], + Rule: parts[1], + Resource: parts[2], + Namespace: parts[3], + Kind: parts[4], + PatchedResource: parts[5], + Result: status, + } + } + return nil +} diff --git a/cmd/cli/kubectl-kyverno/main.go b/cmd/cli/kubectl-kyverno/main.go index a5b18d1623..0d615333d6 100644 --- a/cmd/cli/kubectl-kyverno/main.go +++ b/cmd/cli/kubectl-kyverno/main.go @@ -6,6 +6,7 @@ import ( "strconv" "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/apply" + "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/create" "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/jp" "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/oci" "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/test" @@ -48,7 +49,7 @@ func enableExperimental() bool { } func registerCommands(cli *cobra.Command) { - cli.AddCommand(version.Command(), apply.Command(), test.Command(), jp.Command()) + cli.AddCommand(version.Command(), create.Command(), apply.Command(), test.Command(), jp.Command()) if enableExperimental() { cli.AddCommand(oci.Command()) }