mirror of
https://github.com/kyverno/kyverno.git
synced 2024-12-14 11:57:48 +00:00
chore: add cli commands unit tests (#8366)
* chore: add cli unit tests Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com> * chore: add cli commands unit tests Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com> --------- Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>
This commit is contained in:
parent
fb97629ab5
commit
d24b0848a6
45 changed files with 847 additions and 378 deletions
|
@ -18,9 +18,10 @@ func RootCommand(experimental bool) *cobra.Command {
|
|||
Use: "kyverno",
|
||||
Short: command.FormatDescription(true, websiteUrl, false, description...),
|
||||
Long: command.FormatDescription(false, websiteUrl, false, description...),
|
||||
Args: cobra.NoArgs,
|
||||
SilenceErrors: true,
|
||||
SilenceUsage: true,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
RunE: func(cmd *cobra.Command, _ []string) error {
|
||||
return cmd.Help()
|
||||
},
|
||||
}
|
||||
|
|
|
@ -12,10 +12,13 @@ import (
|
|||
|
||||
func Command() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "create",
|
||||
Short: command.FormatDescription(true, websiteUrl, false, description...),
|
||||
Long: command.FormatDescription(false, websiteUrl, false, description...),
|
||||
Example: command.FormatExamples(examples...),
|
||||
Use: "create",
|
||||
Short: command.FormatDescription(true, websiteUrl, false, description...),
|
||||
Long: command.FormatDescription(false, websiteUrl, false, description...),
|
||||
Example: command.FormatExamples(examples...),
|
||||
Args: cobra.NoArgs,
|
||||
SilenceErrors: true,
|
||||
SilenceUsage: true,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return cmd.Help()
|
||||
},
|
||||
|
|
22
cmd/cli/kubectl-kyverno/commands/create/command_test.go
Normal file
22
cmd/cli/kubectl-kyverno/commands/create/command_test.go
Normal file
|
@ -0,0 +1,22 @@
|
|||
package create
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestCommand(t *testing.T) {
|
||||
cmd := Command()
|
||||
assert.NotNil(t, cmd)
|
||||
err := cmd.Execute()
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestCommandWithArgs(t *testing.T) {
|
||||
cmd := Command()
|
||||
assert.NotNil(t, cmd)
|
||||
cmd.SetArgs([]string{"foo"})
|
||||
err := cmd.Execute()
|
||||
assert.Error(t, err)
|
||||
}
|
|
@ -27,11 +27,13 @@ func Command() *cobra.Command {
|
|||
var rules, any, all []string
|
||||
var options options
|
||||
cmd := &cobra.Command{
|
||||
Use: "exception [name]",
|
||||
Short: command.FormatDescription(true, websiteUrl, false, description...),
|
||||
Long: command.FormatDescription(false, websiteUrl, false, description...),
|
||||
Example: command.FormatExamples(examples...),
|
||||
Args: cobra.ExactArgs(1),
|
||||
Use: "exception [name]",
|
||||
Short: command.FormatDescription(true, websiteUrl, false, description...),
|
||||
Long: command.FormatDescription(false, websiteUrl, false, description...),
|
||||
Example: command.FormatExamples(examples...),
|
||||
Args: cobra.ExactArgs(1),
|
||||
SilenceErrors: true,
|
||||
SilenceUsage: true,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
tmpl, err := template.New("exception").Parse(templates.ExceptionTemplate)
|
||||
if err != nil {
|
||||
|
|
|
@ -25,16 +25,19 @@ func Command() *cobra.Command {
|
|||
var path string
|
||||
var options options
|
||||
cmd := &cobra.Command{
|
||||
Use: "metrics-config",
|
||||
Short: command.FormatDescription(true, websiteUrl, false, description...),
|
||||
Long: command.FormatDescription(false, websiteUrl, false, description...),
|
||||
Example: command.FormatExamples(examples...),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
Use: "metrics-config",
|
||||
Short: command.FormatDescription(true, websiteUrl, false, description...),
|
||||
Long: command.FormatDescription(false, websiteUrl, false, description...),
|
||||
Example: command.FormatExamples(examples...),
|
||||
Args: cobra.NoArgs,
|
||||
SilenceErrors: true,
|
||||
SilenceUsage: true,
|
||||
RunE: func(cmd *cobra.Command, _ []string) error {
|
||||
tmpl, err := template.New("metricsconfig").Funcs(sprig.HermeticTxtFuncMap()).Parse(templates.MetricsConfigTemplate)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
output := os.Stdout
|
||||
output := cmd.OutOrStdout()
|
||||
if path != "" {
|
||||
file, err := os.Create(path)
|
||||
if err != nil {
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
package metricsconfig
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestCommand(t *testing.T) {
|
||||
cmd := Command()
|
||||
assert.NotNil(t, cmd)
|
||||
err := cmd.Execute()
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestCommandWithArgs(t *testing.T) {
|
||||
cmd := Command()
|
||||
assert.NotNil(t, cmd)
|
||||
cmd.SetArgs([]string{"foo"})
|
||||
err := cmd.Execute()
|
||||
assert.Error(t, err)
|
||||
}
|
|
@ -33,11 +33,14 @@ func Command() *cobra.Command {
|
|||
var options options
|
||||
var pass, fail, skip []string
|
||||
cmd := &cobra.Command{
|
||||
Use: "test",
|
||||
Short: command.FormatDescription(true, websiteUrl, false, description...),
|
||||
Long: command.FormatDescription(false, websiteUrl, false, description...),
|
||||
Example: command.FormatExamples(examples...),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
Use: "test",
|
||||
Short: command.FormatDescription(true, websiteUrl, false, description...),
|
||||
Long: command.FormatDescription(false, websiteUrl, false, description...),
|
||||
Example: command.FormatExamples(examples...),
|
||||
Args: cobra.NoArgs,
|
||||
SilenceErrors: true,
|
||||
SilenceUsage: true,
|
||||
RunE: func(cmd *cobra.Command, _ []string) error {
|
||||
tmpl, err := template.New("test").Parse(templates.TestTemplate)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -60,7 +63,7 @@ func Command() *cobra.Command {
|
|||
options.Results = append(options.Results, result)
|
||||
}
|
||||
}
|
||||
output := os.Stdout
|
||||
output := cmd.OutOrStdout()
|
||||
if path != "" {
|
||||
file, err := os.Create(path)
|
||||
if err != nil {
|
||||
|
|
22
cmd/cli/kubectl-kyverno/commands/create/test/command_test.go
Normal file
22
cmd/cli/kubectl-kyverno/commands/create/test/command_test.go
Normal file
|
@ -0,0 +1,22 @@
|
|||
package test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestCommand(t *testing.T) {
|
||||
cmd := Command()
|
||||
assert.NotNil(t, cmd)
|
||||
err := cmd.Execute()
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestCommandWithArgs(t *testing.T) {
|
||||
cmd := Command()
|
||||
assert.NotNil(t, cmd)
|
||||
cmd.SetArgs([]string{"foo"})
|
||||
err := cmd.Execute()
|
||||
assert.Error(t, err)
|
||||
}
|
|
@ -16,16 +16,19 @@ func Command() *cobra.Command {
|
|||
var username string
|
||||
var roles, clusterRoles, groups []string
|
||||
cmd := &cobra.Command{
|
||||
Use: "user-info",
|
||||
Short: command.FormatDescription(true, websiteUrl, false, description...),
|
||||
Long: command.FormatDescription(false, websiteUrl, false, description...),
|
||||
Example: command.FormatExamples(examples...),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
Use: "user-info",
|
||||
Short: command.FormatDescription(true, websiteUrl, false, description...),
|
||||
Long: command.FormatDescription(false, websiteUrl, false, description...),
|
||||
Example: command.FormatExamples(examples...),
|
||||
Args: cobra.NoArgs,
|
||||
SilenceErrors: true,
|
||||
SilenceUsage: true,
|
||||
RunE: func(cmd *cobra.Command, _ []string) error {
|
||||
tmpl, err := template.New("userinfo").Parse(templates.UserInfoTemplate)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
output := os.Stdout
|
||||
output := cmd.OutOrStdout()
|
||||
if path != "" {
|
||||
file, err := os.Create(path)
|
||||
if err != nil {
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
package userinfo
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestCommand(t *testing.T) {
|
||||
cmd := Command()
|
||||
assert.NotNil(t, cmd)
|
||||
err := cmd.Execute()
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestCommandWithArgs(t *testing.T) {
|
||||
cmd := Command()
|
||||
assert.NotNil(t, cmd)
|
||||
cmd.SetArgs([]string{"foo"})
|
||||
err := cmd.Execute()
|
||||
assert.Error(t, err)
|
||||
}
|
|
@ -15,16 +15,19 @@ func Command() *cobra.Command {
|
|||
var path string
|
||||
var globalValues, namespaceSelector, rules, resources []string
|
||||
cmd := &cobra.Command{
|
||||
Use: "values",
|
||||
Short: command.FormatDescription(true, websiteUrl, false, description...),
|
||||
Long: command.FormatDescription(false, websiteUrl, false, description...),
|
||||
Example: command.FormatExamples(examples...),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
Use: "values",
|
||||
Short: command.FormatDescription(true, websiteUrl, false, description...),
|
||||
Long: command.FormatDescription(false, websiteUrl, false, description...),
|
||||
Example: command.FormatExamples(examples...),
|
||||
Args: cobra.NoArgs,
|
||||
SilenceErrors: true,
|
||||
SilenceUsage: true,
|
||||
RunE: func(cmd *cobra.Command, _ []string) error {
|
||||
tmpl, err := template.New("values").Parse(templates.ValuesTemplate)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
output := os.Stdout
|
||||
output := cmd.OutOrStdout()
|
||||
if path != "" {
|
||||
file, err := os.Create(path)
|
||||
if err != nil {
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
package values
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestCommand(t *testing.T) {
|
||||
cmd := Command()
|
||||
assert.NotNil(t, cmd)
|
||||
err := cmd.Execute()
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestCommandWithArgs(t *testing.T) {
|
||||
cmd := Command()
|
||||
assert.NotNil(t, cmd)
|
||||
cmd.SetArgs([]string{"foo"})
|
||||
err := cmd.Execute()
|
||||
assert.Error(t, err)
|
||||
}
|
|
@ -1,74 +1,32 @@
|
|||
package docs
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/command"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/cobra/doc"
|
||||
)
|
||||
|
||||
const fmTemplate = `---
|
||||
date: %s
|
||||
title: "%s"
|
||||
weight: 35
|
||||
---
|
||||
`
|
||||
|
||||
func websitePrepender(filename string) string {
|
||||
now := time.Now().Format(time.RFC3339)
|
||||
name := filepath.Base(filename)
|
||||
base := strings.TrimSuffix(name, path.Ext(name))
|
||||
return fmt.Sprintf(fmTemplate, now, strings.Replace(base, "_", " ", -1))
|
||||
}
|
||||
|
||||
func websiteLinkHandler(filename string) string {
|
||||
return "../" + strings.TrimSuffix(filename, filepath.Ext(filename))
|
||||
}
|
||||
|
||||
func identity(s string) string {
|
||||
return s
|
||||
}
|
||||
|
||||
func empty(s string) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func Command(root *cobra.Command) *cobra.Command {
|
||||
var path string
|
||||
var website bool
|
||||
var autogenTag bool
|
||||
var options options
|
||||
cmd := &cobra.Command{
|
||||
Use: "docs",
|
||||
Short: command.FormatDescription(true, websiteUrl, false, description...),
|
||||
Long: command.FormatDescription(false, websiteUrl, false, description...),
|
||||
Example: command.FormatExamples(examples...),
|
||||
RunE: func(_ *cobra.Command, args []string) error {
|
||||
prepender := empty
|
||||
linkHandler := identity
|
||||
if website {
|
||||
prepender = websitePrepender
|
||||
linkHandler = websiteLinkHandler
|
||||
Args: cobra.NoArgs,
|
||||
RunE: func(cmd *cobra.Command, _ []string) error {
|
||||
if err := options.validate(root); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := os.Stat(path); errors.Is(err, os.ErrNotExist) {
|
||||
if err := os.MkdirAll(path, os.ModeDir|os.ModePerm); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
root.DisableAutoGenTag = !autogenTag
|
||||
return doc.GenMarkdownTreeCustom(root, path, prepender, linkHandler)
|
||||
cmd.SilenceUsage = true
|
||||
cmd.SilenceErrors = true
|
||||
return options.execute(root)
|
||||
},
|
||||
}
|
||||
cmd.Flags().StringVarP(&path, "output", "o", ".", "Output path")
|
||||
cmd.Flags().BoolVar(&website, "website", false, "Website version")
|
||||
cmd.Flags().BoolVar(&autogenTag, "autogenTag", true, "Determines if the generated docs should contain a timestamp")
|
||||
cmd.Flags().StringVarP(&options.path, "output", "o", ".", "Output path")
|
||||
cmd.Flags().BoolVar(&options.website, "website", false, "Website version")
|
||||
cmd.Flags().BoolVar(&options.autogenTag, "autogenTag", true, "Determines if the generated docs should contain a timestamp")
|
||||
if err := cmd.MarkFlagDirname("output"); err != nil {
|
||||
log.Println("WARNING", err)
|
||||
}
|
||||
|
|
23
cmd/cli/kubectl-kyverno/commands/docs/command_test.go
Normal file
23
cmd/cli/kubectl-kyverno/commands/docs/command_test.go
Normal file
|
@ -0,0 +1,23 @@
|
|||
package docs
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestCommandWithNilRoot(t *testing.T) {
|
||||
cmd := Command(nil)
|
||||
assert.NotNil(t, cmd)
|
||||
cmd.SetArgs([]string{"-o", "foo"})
|
||||
err := cmd.Execute()
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestCommandWithoutArgs(t *testing.T) {
|
||||
cmd := Command(&cobra.Command{})
|
||||
assert.NotNil(t, cmd)
|
||||
err := cmd.Execute()
|
||||
assert.Error(t, err)
|
||||
}
|
41
cmd/cli/kubectl-kyverno/commands/docs/options.go
Normal file
41
cmd/cli/kubectl-kyverno/commands/docs/options.go
Normal file
|
@ -0,0 +1,41 @@
|
|||
package docs
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/cobra/doc"
|
||||
)
|
||||
|
||||
type options struct {
|
||||
path string
|
||||
website bool
|
||||
autogenTag bool
|
||||
}
|
||||
|
||||
func (o options) validate(root *cobra.Command) error {
|
||||
if o.path == "" {
|
||||
return errors.New("path is required")
|
||||
}
|
||||
if root == nil {
|
||||
return errors.New("root command is required")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o options) execute(root *cobra.Command) error {
|
||||
prepender := empty
|
||||
linkHandler := identity
|
||||
if o.website {
|
||||
prepender = websitePrepender
|
||||
linkHandler = websiteLinkHandler
|
||||
}
|
||||
if _, err := os.Stat(o.path); errors.Is(err, os.ErrNotExist) {
|
||||
if err := os.MkdirAll(o.path, os.ModeDir|os.ModePerm); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
root.DisableAutoGenTag = !o.autogenTag
|
||||
return doc.GenMarkdownTreeCustom(root, o.path, prepender, linkHandler)
|
||||
}
|
35
cmd/cli/kubectl-kyverno/commands/docs/utils.go
Normal file
35
cmd/cli/kubectl-kyverno/commands/docs/utils.go
Normal file
|
@ -0,0 +1,35 @@
|
|||
package docs
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const fmTemplate = `---
|
||||
date: %s
|
||||
title: "%s"
|
||||
weight: 35
|
||||
---
|
||||
`
|
||||
|
||||
func websitePrepender(filename string) string {
|
||||
now := time.Now().Format(time.RFC3339)
|
||||
name := filepath.Base(filename)
|
||||
base := strings.TrimSuffix(name, path.Ext(name))
|
||||
return fmt.Sprintf(fmTemplate, now, strings.Replace(base, "_", " ", -1))
|
||||
}
|
||||
|
||||
func websiteLinkHandler(filename string) string {
|
||||
return "../" + strings.TrimSuffix(filename, filepath.Ext(filename))
|
||||
}
|
||||
|
||||
func identity(s string) string {
|
||||
return s
|
||||
}
|
||||
|
||||
func empty(s string) string {
|
||||
return ""
|
||||
}
|
|
@ -8,10 +8,13 @@ import (
|
|||
|
||||
func Command() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "fix",
|
||||
Short: command.FormatDescription(true, websiteUrl, true, description...),
|
||||
Long: command.FormatDescription(false, websiteUrl, true, description...),
|
||||
Example: command.FormatExamples(examples...),
|
||||
Use: "fix",
|
||||
Short: command.FormatDescription(true, websiteUrl, true, description...),
|
||||
Long: command.FormatDescription(false, websiteUrl, true, description...),
|
||||
Example: command.FormatExamples(examples...),
|
||||
Args: cobra.NoArgs,
|
||||
SilenceErrors: true,
|
||||
SilenceUsage: true,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return cmd.Help()
|
||||
},
|
||||
|
|
22
cmd/cli/kubectl-kyverno/commands/fix/command_test.go
Normal file
22
cmd/cli/kubectl-kyverno/commands/fix/command_test.go
Normal file
|
@ -0,0 +1,22 @@
|
|||
package fix
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestCommand(t *testing.T) {
|
||||
cmd := Command()
|
||||
assert.NotNil(t, cmd)
|
||||
err := cmd.Execute()
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestCommandWithArgs(t *testing.T) {
|
||||
cmd := Command()
|
||||
assert.NotNil(t, cmd)
|
||||
cmd.SetArgs([]string{"foo"})
|
||||
err := cmd.Execute()
|
||||
assert.Error(t, err)
|
||||
}
|
|
@ -8,17 +8,18 @@ import (
|
|||
func Command() *cobra.Command {
|
||||
var options options
|
||||
cmd := &cobra.Command{
|
||||
Use: "test [folder]...",
|
||||
Use: "test [dir]...",
|
||||
Short: command.FormatDescription(true, websiteUrl, true, description...),
|
||||
Long: command.FormatDescription(false, websiteUrl, true, description...),
|
||||
Example: command.FormatExamples(examples...),
|
||||
Args: cobra.MinimumNArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if err := options.validate(); err != nil {
|
||||
if err := options.validate(args...); err != nil {
|
||||
return err
|
||||
}
|
||||
cmd.SilenceUsage = true
|
||||
cmd.SilenceErrors = true
|
||||
return options.execute(args...)
|
||||
return options.execute(cmd.OutOrStdout(), args...)
|
||||
},
|
||||
}
|
||||
cmd.Flags().StringVarP(&options.fileName, "file-name", "f", "kyverno-test.yaml", "Test filename")
|
||||
|
|
22
cmd/cli/kubectl-kyverno/commands/fix/test/command_test.go
Normal file
22
cmd/cli/kubectl-kyverno/commands/fix/test/command_test.go
Normal file
|
@ -0,0 +1,22 @@
|
|||
package test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestCommand(t *testing.T) {
|
||||
cmd := Command()
|
||||
assert.NotNil(t, cmd)
|
||||
err := cmd.Execute()
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestCommandInvalidFileName(t *testing.T) {
|
||||
cmd := Command()
|
||||
assert.NotNil(t, cmd)
|
||||
cmd.SetArgs([]string{"foo", "-f", ""})
|
||||
err := cmd.Execute()
|
||||
assert.Error(t, err)
|
||||
}
|
|
@ -3,6 +3,7 @@ package test
|
|||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
|
@ -17,16 +18,19 @@ type options struct {
|
|||
compress bool
|
||||
}
|
||||
|
||||
func (o options) validate() error {
|
||||
func (o options) validate(dirs ...string) error {
|
||||
if o.fileName == "" {
|
||||
return errors.New("file-name must not be set to an empty string")
|
||||
}
|
||||
if len(dirs) == 0 {
|
||||
return errors.New("at least one test directory is required")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o options) execute(args ...string) error {
|
||||
func (o options) execute(out io.Writer, dirs ...string) error {
|
||||
var testCases []test.TestCase
|
||||
for _, arg := range args {
|
||||
for _, arg := range dirs {
|
||||
tests, err := test.LoadTests(arg, o.fileName)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -34,48 +38,48 @@ func (o options) execute(args ...string) error {
|
|||
testCases = append(testCases, tests...)
|
||||
}
|
||||
for _, testCase := range testCases {
|
||||
fmt.Printf("Processing test file (%s)...", testCase.Path)
|
||||
fmt.Println()
|
||||
fmt.Fprintf(out, "Processing test file (%s)...", testCase.Path)
|
||||
fmt.Fprintln(out)
|
||||
if testCase.Err != nil {
|
||||
fmt.Printf(" ERROR: loading test file (%s): %s", testCase.Path, testCase.Err)
|
||||
fmt.Println()
|
||||
fmt.Fprintf(out, " ERROR: loading test file (%s): %s", testCase.Path, testCase.Err)
|
||||
fmt.Fprintln(out)
|
||||
continue
|
||||
}
|
||||
test := testCase.Test
|
||||
needsSave := false
|
||||
if test.Name == "" {
|
||||
fmt.Println(" WARNING: name is not set")
|
||||
fmt.Fprintln(out, " WARNING: name is not set")
|
||||
test.Name = filepath.Base(testCase.Path)
|
||||
needsSave = true
|
||||
}
|
||||
if len(test.Policies) == 0 {
|
||||
fmt.Println(" WARNING: test has no policies")
|
||||
fmt.Fprintln(out, " WARNING: test has no policies")
|
||||
}
|
||||
if len(test.Resources) == 0 {
|
||||
fmt.Println(" WARNING: test has no resources")
|
||||
fmt.Fprintln(out, " WARNING: test has no resources")
|
||||
}
|
||||
for i := range test.Results {
|
||||
result := &test.Results[i]
|
||||
if result.Resource != "" && len(result.Resources) != 0 {
|
||||
fmt.Println(" WARNING: test result should not use both `resource` and `resources` fields")
|
||||
fmt.Fprintln(out, " WARNING: test result should not use both `resource` and `resources` fields")
|
||||
}
|
||||
if result.Resource != "" {
|
||||
fmt.Println(" WARNING: test result uses deprecated `resource` field, moving it into the `resources` field")
|
||||
fmt.Fprintln(out, " WARNING: test result uses deprecated `resource` field, moving it into the `resources` field")
|
||||
result.Resources = append(result.Resources, result.Resource)
|
||||
result.Resource = ""
|
||||
needsSave = true
|
||||
}
|
||||
if result.Namespace != "" {
|
||||
fmt.Println(" WARNING: test result uses deprecated `namespace` field, replacing `policy` with a `<namespace>/<name>` pattern")
|
||||
fmt.Fprintln(out, " WARNING: test result uses deprecated `namespace` field, replacing `policy` with a `<namespace>/<name>` pattern")
|
||||
result.Policy = fmt.Sprintf("%s/%s", result.Namespace, result.Policy)
|
||||
result.Namespace = ""
|
||||
needsSave = true
|
||||
}
|
||||
if result.Status != "" && result.Result != "" {
|
||||
fmt.Println(" ERROR: test result should not use both `status` and `result` fields")
|
||||
fmt.Fprintln(out, " ERROR: test result should not use both `status` and `result` fields")
|
||||
}
|
||||
if result.Status != "" && result.Result == "" {
|
||||
fmt.Println(" WARNING: test result uses deprecated `status` field, moving it into the `result` field")
|
||||
fmt.Fprintln(out, " WARNING: test result uses deprecated `status` field, moving it into the `result` field")
|
||||
result.Result = result.Status
|
||||
result.Status = ""
|
||||
needsSave = true
|
||||
|
@ -98,23 +102,23 @@ func (o options) execute(args ...string) error {
|
|||
}
|
||||
}
|
||||
if o.save && needsSave {
|
||||
fmt.Printf(" Saving test file (%s)...", testCase.Path)
|
||||
fmt.Println()
|
||||
fmt.Fprintf(out, " Saving test file (%s)...", testCase.Path)
|
||||
fmt.Fprintln(out)
|
||||
yamlBytes, err := yaml.Marshal(test)
|
||||
if err != nil {
|
||||
fmt.Printf(" ERROR: converting test to yaml: %s", err)
|
||||
fmt.Println()
|
||||
fmt.Fprintf(out, " ERROR: converting test to yaml: %s", err)
|
||||
fmt.Fprintln(out)
|
||||
continue
|
||||
}
|
||||
if err := os.WriteFile(testCase.Path, yamlBytes, os.ModePerm); err != nil {
|
||||
fmt.Printf(" ERROR: saving test file (%s): %s", testCase.Path, err)
|
||||
fmt.Println()
|
||||
fmt.Fprintf(out, " ERROR: saving test file (%s): %s", testCase.Path, err)
|
||||
fmt.Fprintln(out)
|
||||
continue
|
||||
}
|
||||
fmt.Println(" OK")
|
||||
fmt.Fprintln(out, " OK")
|
||||
}
|
||||
fmt.Println()
|
||||
fmt.Fprintln(out)
|
||||
}
|
||||
fmt.Println("Done.")
|
||||
fmt.Fprintln(out, "Done.")
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -10,16 +10,21 @@ import (
|
|||
|
||||
func Command() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "jp",
|
||||
Short: command.FormatDescription(true, websiteUrl, false, description...),
|
||||
Long: command.FormatDescription(false, websiteUrl, false, description...),
|
||||
Example: command.FormatExamples(examples...),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
Use: "jp",
|
||||
Short: command.FormatDescription(true, websiteUrl, false, description...),
|
||||
Long: command.FormatDescription(false, websiteUrl, false, description...),
|
||||
Example: command.FormatExamples(examples...),
|
||||
Args: cobra.NoArgs,
|
||||
SilenceErrors: true,
|
||||
SilenceUsage: true,
|
||||
RunE: func(cmd *cobra.Command, _ []string) error {
|
||||
return cmd.Help()
|
||||
},
|
||||
}
|
||||
cmd.AddCommand(query.Command())
|
||||
cmd.AddCommand(function.Command())
|
||||
cmd.AddCommand(parse.Command())
|
||||
cmd.AddCommand(
|
||||
function.Command(),
|
||||
parse.Command(),
|
||||
query.Command(),
|
||||
)
|
||||
return cmd
|
||||
}
|
||||
|
|
22
cmd/cli/kubectl-kyverno/commands/jp/command_test.go
Normal file
22
cmd/cli/kubectl-kyverno/commands/jp/command_test.go
Normal file
|
@ -0,0 +1,22 @@
|
|||
package jp
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestCommand(t *testing.T) {
|
||||
cmd := Command()
|
||||
assert.NotNil(t, cmd)
|
||||
err := cmd.Execute()
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestCommandWithArgs(t *testing.T) {
|
||||
cmd := Command()
|
||||
assert.NotNil(t, cmd)
|
||||
cmd.SetArgs([]string{"foo"})
|
||||
err := cmd.Execute()
|
||||
assert.Error(t, err)
|
||||
}
|
|
@ -2,6 +2,7 @@ package function
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/command"
|
||||
"github.com/kyverno/kyverno/pkg/config"
|
||||
|
@ -13,18 +14,19 @@ import (
|
|||
|
||||
func Command() *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "function [function_name]...",
|
||||
Short: command.FormatDescription(true, websiteUrl, false, description...),
|
||||
Long: command.FormatDescription(false, websiteUrl, false, description...),
|
||||
Example: command.FormatExamples(examples...),
|
||||
SilenceUsage: true,
|
||||
Use: "function [function_name]...",
|
||||
Short: command.FormatDescription(true, websiteUrl, false, description...),
|
||||
Long: command.FormatDescription(false, websiteUrl, false, description...),
|
||||
Example: command.FormatExamples(examples...),
|
||||
SilenceErrors: true,
|
||||
SilenceUsage: true,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
printFunctions(args...)
|
||||
printFunctions(cmd.OutOrStdout(), args...)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func printFunctions(names ...string) {
|
||||
func printFunctions(out io.Writer, names ...string) {
|
||||
functions := jmespath.GetFunctions(config.NewDefaultConfiguration(false))
|
||||
slices.SortFunc(functions, func(a, b jmespath.FunctionEntry) bool {
|
||||
return a.String() < b.String()
|
||||
|
@ -34,12 +36,12 @@ func printFunctions(names ...string) {
|
|||
if len(namesSet) == 0 || namesSet.Has(function.Name) {
|
||||
note := function.Note
|
||||
function.Note = ""
|
||||
fmt.Println("Name:", function.Name)
|
||||
fmt.Println(" Signature:", function.String())
|
||||
fmt.Fprintln(out, "Name:", function.Name)
|
||||
fmt.Fprintln(out, " Signature:", function.String())
|
||||
if note != "" {
|
||||
fmt.Println(" Note: ", note)
|
||||
fmt.Fprintln(out, " Note: ", note)
|
||||
}
|
||||
fmt.Println()
|
||||
fmt.Fprintln(out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
30
cmd/cli/kubectl-kyverno/commands/jp/function/command_test.go
Normal file
30
cmd/cli/kubectl-kyverno/commands/jp/function/command_test.go
Normal file
|
@ -0,0 +1,30 @@
|
|||
package function
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestCommand(t *testing.T) {
|
||||
cmd := Command()
|
||||
assert.NotNil(t, cmd)
|
||||
err := cmd.Execute()
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestCommandWithOneArg(t *testing.T) {
|
||||
cmd := Command()
|
||||
assert.NotNil(t, cmd)
|
||||
cmd.SetArgs([]string{"truncate"})
|
||||
err := cmd.Execute()
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestCommandWithArgs(t *testing.T) {
|
||||
cmd := Command()
|
||||
assert.NotNil(t, cmd)
|
||||
cmd.SetArgs([]string{"truncate", "to_upper"})
|
||||
err := cmd.Execute()
|
||||
assert.NoError(t, err)
|
||||
}
|
|
@ -14,18 +14,19 @@ import (
|
|||
func Command() *cobra.Command {
|
||||
var files []string
|
||||
cmd := &cobra.Command{
|
||||
Use: "parse [-f file|expression]...",
|
||||
Short: command.FormatDescription(true, websiteUrl, false, description...),
|
||||
Long: command.FormatDescription(false, websiteUrl, false, description...),
|
||||
Example: command.FormatExamples(examples...),
|
||||
SilenceUsage: true,
|
||||
Use: "parse [-f file|expression]...",
|
||||
Short: command.FormatDescription(true, websiteUrl, false, description...),
|
||||
Long: command.FormatDescription(false, websiteUrl, false, description...),
|
||||
Example: command.FormatExamples(examples...),
|
||||
SilenceErrors: true,
|
||||
SilenceUsage: true,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
expressions, err := loadExpressions(cmd, args, files)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, expression := range expressions {
|
||||
if err := printAst(expression); err != nil {
|
||||
if err := printAst(cmd.OutOrStdout(), expression); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
@ -44,14 +45,14 @@ func readFile(reader io.Reader) (string, error) {
|
|||
return string(data), nil
|
||||
}
|
||||
|
||||
func loadFile(file string) (string, error) {
|
||||
func loadFile(cmd *cobra.Command, file string) (string, error) {
|
||||
reader, err := os.Open(filepath.Clean(file))
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed open file %s: %v", file, err)
|
||||
}
|
||||
defer func() {
|
||||
if err := reader.Close(); err != nil {
|
||||
fmt.Printf("Error closing file: %s\n", err)
|
||||
fmt.Fprintf(cmd.OutOrStdout(), "Error closing file: %s\n", err)
|
||||
}
|
||||
}()
|
||||
content, err := readFile(reader)
|
||||
|
@ -65,15 +66,15 @@ func loadExpressions(cmd *cobra.Command, args []string, files []string) ([]strin
|
|||
var expressions []string
|
||||
expressions = append(expressions, args...)
|
||||
for _, file := range files {
|
||||
expression, err := loadFile(file)
|
||||
expression, err := loadFile(cmd, file)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
expressions = append(expressions, expression)
|
||||
}
|
||||
if len(expressions) == 0 {
|
||||
fmt.Println("Reading from terminal input.")
|
||||
fmt.Println("Enter a jmespath expression and hit Ctrl+D.")
|
||||
fmt.Fprintln(cmd.OutOrStdout(), "Reading from terminal input.")
|
||||
fmt.Fprintln(cmd.OutOrStdout(), "Enter a jmespath expression and hit Ctrl+D.")
|
||||
data, err := readFile(cmd.InOrStdin())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read file STDIN: %v", err)
|
||||
|
@ -85,7 +86,7 @@ func loadExpressions(cmd *cobra.Command, args []string, files []string) ([]strin
|
|||
|
||||
// The following function has been adapted from
|
||||
// https://github.com/jmespath/jp/blob/54882e03bd277fc4475a677fab1d35eaa478b839/jp.go
|
||||
func printAst(expression string) error {
|
||||
func printAst(out io.Writer, expression string) error {
|
||||
parser := gojmespath.NewParser()
|
||||
parsed, err := parser.Parse(expression)
|
||||
if err != nil {
|
||||
|
@ -94,7 +95,7 @@ func printAst(expression string) error {
|
|||
}
|
||||
return err
|
||||
}
|
||||
fmt.Println("#", expression)
|
||||
fmt.Println(parsed)
|
||||
fmt.Fprintln(out, "#", expression)
|
||||
fmt.Fprintln(out, parsed)
|
||||
return nil
|
||||
}
|
||||
|
|
15
cmd/cli/kubectl-kyverno/commands/jp/parse/command_test.go
Normal file
15
cmd/cli/kubectl-kyverno/commands/jp/parse/command_test.go
Normal file
|
@ -0,0 +1,15 @@
|
|||
package parse
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestCommand(t *testing.T) {
|
||||
cmd := Command()
|
||||
assert.NotNil(t, cmd)
|
||||
cmd.SetArgs([]string{"request.object.metadata.name | truncate(@, `9`)"})
|
||||
err := cmd.Execute()
|
||||
assert.NoError(t, err)
|
||||
}
|
|
@ -21,17 +21,18 @@ func Command() *cobra.Command {
|
|||
var input string
|
||||
var queries []string
|
||||
cmd := &cobra.Command{
|
||||
Use: "query [-i input] [-q query|query]...",
|
||||
Short: command.FormatDescription(true, websiteUrl, false, description...),
|
||||
Long: command.FormatDescription(false, websiteUrl, false, description...),
|
||||
Example: command.FormatExamples(examples...),
|
||||
SilenceUsage: true,
|
||||
Use: "query [-i input] [-q query|query]...",
|
||||
Short: command.FormatDescription(true, websiteUrl, false, description...),
|
||||
Long: command.FormatDescription(false, websiteUrl, false, description...),
|
||||
Example: command.FormatExamples(examples...),
|
||||
SilenceErrors: true,
|
||||
SilenceUsage: true,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
queries, err := loadQueries(args, queries)
|
||||
queries, err := loadQueries(cmd, args, queries)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
input, err := loadInput(input)
|
||||
input, err := loadInput(cmd, input)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -57,7 +58,7 @@ func Command() *cobra.Command {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := printResult(query, result, unquoted, compact); err != nil {
|
||||
if err := printResult(cmd, query, result, unquoted, compact); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
@ -79,14 +80,14 @@ func readFile(reader io.Reader) ([]byte, error) {
|
|||
return data, nil
|
||||
}
|
||||
|
||||
func loadFile(file string) ([]byte, error) {
|
||||
func loadFile(cmd *cobra.Command, file string) ([]byte, error) {
|
||||
reader, err := os.Open(filepath.Clean(file))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed open file %s: %v", file, err)
|
||||
}
|
||||
defer func() {
|
||||
if err := reader.Close(); err != nil {
|
||||
fmt.Printf("Error closing file: %s\n", err)
|
||||
fmt.Fprintf(cmd.OutOrStdout(), "Error closing file: %s\n", err)
|
||||
}
|
||||
}()
|
||||
content, err := readFile(reader)
|
||||
|
@ -97,8 +98,8 @@ func loadFile(file string) ([]byte, error) {
|
|||
}
|
||||
|
||||
func readQuery(cmd *cobra.Command) (string, error) {
|
||||
fmt.Println("Reading from terminal input.")
|
||||
fmt.Println("Enter a jmespath expression and hit Ctrl+D.")
|
||||
fmt.Fprintln(cmd.OutOrStdout(), "Reading from terminal input.")
|
||||
fmt.Fprintln(cmd.OutOrStdout(), "Enter a jmespath expression and hit Ctrl+D.")
|
||||
data, err := readFile(cmd.InOrStdin())
|
||||
if err != nil {
|
||||
return "", err
|
||||
|
@ -106,11 +107,11 @@ func readQuery(cmd *cobra.Command) (string, error) {
|
|||
return string(data), nil
|
||||
}
|
||||
|
||||
func loadQueries(args []string, files []string) ([]string, error) {
|
||||
func loadQueries(cmd *cobra.Command, args []string, files []string) ([]string, error) {
|
||||
var queries []string
|
||||
queries = append(queries, args...)
|
||||
for _, file := range files {
|
||||
query, err := loadFile(file)
|
||||
query, err := loadFile(cmd, file)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -120,8 +121,8 @@ func loadQueries(args []string, files []string) ([]string, error) {
|
|||
}
|
||||
|
||||
func readInput(cmd *cobra.Command) (interface{}, error) {
|
||||
fmt.Println("Reading from terminal input.")
|
||||
fmt.Println("Enter input object and hit Ctrl+D.")
|
||||
fmt.Fprintln(cmd.OutOrStdout(), "Reading from terminal input.")
|
||||
fmt.Fprintln(cmd.OutOrStdout(), "Enter input object and hit Ctrl+D.")
|
||||
data, err := readFile(cmd.InOrStdin())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -133,11 +134,11 @@ func readInput(cmd *cobra.Command) (interface{}, error) {
|
|||
return input, nil
|
||||
}
|
||||
|
||||
func loadInput(file string) (interface{}, error) {
|
||||
func loadInput(cmd *cobra.Command, file string) (interface{}, error) {
|
||||
if file == "" {
|
||||
return nil, nil
|
||||
}
|
||||
data, err := loadFile(file)
|
||||
data, err := loadFile(cmd, file)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -164,11 +165,11 @@ func evaluate(input interface{}, query string) (interface{}, error) {
|
|||
return result, nil
|
||||
}
|
||||
|
||||
func printResult(query string, result interface{}, unquoted bool, compact bool) error {
|
||||
func printResult(cmd *cobra.Command, query string, result interface{}, unquoted bool, compact bool) error {
|
||||
converted, isString := result.(string)
|
||||
fmt.Println("#", query)
|
||||
fmt.Fprintln(cmd.OutOrStdout(), "#", query)
|
||||
if unquoted && isString {
|
||||
fmt.Println(converted)
|
||||
fmt.Fprintln(cmd.OutOrStdout(), converted)
|
||||
} else {
|
||||
var toJSON []byte
|
||||
var err error
|
||||
|
@ -180,7 +181,7 @@ func printResult(query string, result interface{}, unquoted bool, compact bool)
|
|||
if err != nil {
|
||||
return fmt.Errorf("error marshalling result to JSON: %w", err)
|
||||
}
|
||||
fmt.Println(string(toJSON))
|
||||
fmt.Fprintln(cmd.OutOrStdout(), string(toJSON))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
15
cmd/cli/kubectl-kyverno/commands/jp/query/command_test.go
Normal file
15
cmd/cli/kubectl-kyverno/commands/jp/query/command_test.go
Normal file
|
@ -0,0 +1,15 @@
|
|||
package query
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestCommand(t *testing.T) {
|
||||
cmd := Command()
|
||||
assert.NotNil(t, cmd)
|
||||
cmd.SetArgs([]string{"-i", "object.yaml", "-q", "query-file"})
|
||||
err := cmd.Execute()
|
||||
assert.Error(t, err)
|
||||
}
|
|
@ -19,11 +19,14 @@ func Command() *cobra.Command {
|
|||
registryclient.AzureKeychain,
|
||||
)
|
||||
cmd := &cobra.Command{
|
||||
Use: "oci",
|
||||
Short: command.FormatDescription(true, websiteUrl, true, description...),
|
||||
Long: command.FormatDescription(false, websiteUrl, true, description...),
|
||||
Example: command.FormatExamples(examples...),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
Use: "oci",
|
||||
Short: command.FormatDescription(true, websiteUrl, true, description...),
|
||||
Long: command.FormatDescription(false, websiteUrl, true, description...),
|
||||
Example: command.FormatExamples(examples...),
|
||||
Args: cobra.NoArgs,
|
||||
SilenceErrors: true,
|
||||
SilenceUsage: true,
|
||||
RunE: func(cmd *cobra.Command, _ []string) error {
|
||||
return cmd.Help()
|
||||
},
|
||||
}
|
||||
|
|
22
cmd/cli/kubectl-kyverno/commands/oci/command_test.go
Normal file
22
cmd/cli/kubectl-kyverno/commands/oci/command_test.go
Normal file
|
@ -0,0 +1,22 @@
|
|||
package oci
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestCommand(t *testing.T) {
|
||||
cmd := Command()
|
||||
assert.NotNil(t, cmd)
|
||||
err := cmd.Execute()
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestCommandWithArgs(t *testing.T) {
|
||||
cmd := Command()
|
||||
assert.NotNil(t, cmd)
|
||||
cmd.SetArgs([]string{"foo"})
|
||||
err := cmd.Execute()
|
||||
assert.Error(t, err)
|
||||
}
|
|
@ -1,121 +1,34 @@
|
|||
package pull
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"log"
|
||||
|
||||
securejoin "github.com/cyphar/filepath-securejoin"
|
||||
"github.com/google/go-containerregistry/pkg/authn"
|
||||
"github.com/google/go-containerregistry/pkg/name"
|
||||
"github.com/google/go-containerregistry/pkg/v1/remote"
|
||||
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/command"
|
||||
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/commands/oci/internal"
|
||||
policyutils "github.com/kyverno/kyverno/pkg/utils/policy"
|
||||
yamlutils "github.com/kyverno/kyverno/pkg/utils/yaml"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func Command(keychain authn.Keychain) *cobra.Command {
|
||||
var dir string
|
||||
var imageRef string
|
||||
var options options
|
||||
cmd := &cobra.Command{
|
||||
Use: "pull",
|
||||
Use: "pull [dir]",
|
||||
Short: command.FormatDescription(true, websiteUrl, true, description...),
|
||||
Long: command.FormatDescription(false, websiteUrl, true, description...),
|
||||
Example: command.FormatExamples(examples...),
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if imageRef == "" {
|
||||
return errors.New("image reference is required")
|
||||
dir := args[0]
|
||||
if err := options.validate(dir); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dir = filepath.Clean(dir)
|
||||
if !filepath.IsAbs(dir) {
|
||||
cwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dir, err = securejoin.SecureJoin(cwd, dir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
fi, err := os.Lstat(dir)
|
||||
// Dir does not need to exist, as it can later be created.
|
||||
if err != nil && errors.Is(err, os.ErrNotExist) {
|
||||
if err := os.MkdirAll(dir, 0o750); err != nil {
|
||||
return fmt.Errorf("unable to create directory %s: %w", dir, err)
|
||||
}
|
||||
}
|
||||
|
||||
if err == nil && !fi.IsDir() {
|
||||
return fmt.Errorf("dir '%s' must be a directory", dir)
|
||||
}
|
||||
|
||||
ref, err := name.ParseReference(imageRef)
|
||||
if err != nil {
|
||||
return fmt.Errorf("parsing image reference: %v", err)
|
||||
}
|
||||
|
||||
fmt.Fprintf(os.Stderr, "Downloading policies from an image [%s]...\n", ref.Name())
|
||||
rmt, err := remote.Get(ref, remote.WithContext(cmd.Context()), remote.WithAuthFromKeychain(keychain))
|
||||
if err != nil {
|
||||
return fmt.Errorf("getting image: %v", err)
|
||||
}
|
||||
|
||||
img, err := rmt.Image()
|
||||
if err != nil {
|
||||
return fmt.Errorf("getting image: %v", err)
|
||||
}
|
||||
|
||||
l, err := img.Layers()
|
||||
if err != nil {
|
||||
return fmt.Errorf("getting image layers: %v", err)
|
||||
}
|
||||
|
||||
for _, layer := range l {
|
||||
lmt, err := layer.MediaType()
|
||||
if err != nil {
|
||||
return fmt.Errorf("getting layer media type: %v", err)
|
||||
}
|
||||
|
||||
if lmt == internal.PolicyLayerMediaType {
|
||||
blob, err := layer.Compressed()
|
||||
if err != nil {
|
||||
return fmt.Errorf("getting layer blob: %v", err)
|
||||
}
|
||||
defer blob.Close()
|
||||
|
||||
layerBytes, err := io.ReadAll(blob)
|
||||
if err != nil {
|
||||
return fmt.Errorf("reading layer blob: %v", err)
|
||||
}
|
||||
policies, _, err := yamlutils.GetPolicy(layerBytes)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unmarshaling layer blob: %v", err)
|
||||
}
|
||||
for _, policy := range policies {
|
||||
policyBytes, err := policyutils.ToYaml(policy)
|
||||
if err != nil {
|
||||
return fmt.Errorf("converting policy to yaml: %v", err)
|
||||
}
|
||||
pp := filepath.Join(dir, policy.GetName()+".yaml")
|
||||
fmt.Fprintf(os.Stderr, "Saving policy into disk [%s]...\n", pp)
|
||||
if err := os.WriteFile(pp, policyBytes, 0o600); err != nil {
|
||||
return fmt.Errorf("creating file: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, "Done.")
|
||||
return nil
|
||||
cmd.SilenceUsage = true
|
||||
cmd.SilenceErrors = true
|
||||
return options.execute(cmd.Context(), dir, keychain)
|
||||
},
|
||||
}
|
||||
cmd.Flags().StringVarP(&dir, "directory", "d", ".", "path to a directory")
|
||||
cmd.Flags().StringVarP(&imageRef, "image", "i", "", "image reference to push to or pull from")
|
||||
cmd.Flags().StringVarP(&options.imageRef, "image", "i", "", "image reference to push to or pull from")
|
||||
if err := cmd.MarkFlagRequired("image"); err != nil {
|
||||
log.Println("WARNING", err)
|
||||
}
|
||||
return cmd
|
||||
}
|
||||
|
|
33
cmd/cli/kubectl-kyverno/commands/oci/pull/command_test.go
Normal file
33
cmd/cli/kubectl-kyverno/commands/oci/pull/command_test.go
Normal file
|
@ -0,0 +1,33 @@
|
|||
package pull
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-containerregistry/pkg/authn"
|
||||
"github.com/google/go-containerregistry/pkg/authn/github"
|
||||
"github.com/kyverno/kyverno/pkg/registryclient"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var keychain = authn.NewMultiKeychain(
|
||||
authn.DefaultKeychain,
|
||||
github.Keychain,
|
||||
registryclient.AWSKeychain,
|
||||
registryclient.GCPKeychain,
|
||||
registryclient.AzureKeychain,
|
||||
)
|
||||
|
||||
func TestCommandNoImageRef(t *testing.T) {
|
||||
cmd := Command(keychain)
|
||||
assert.NotNil(t, cmd)
|
||||
err := cmd.Execute()
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestCommandWithArgs(t *testing.T) {
|
||||
cmd := Command(keychain)
|
||||
assert.NotNil(t, cmd)
|
||||
cmd.SetArgs([]string{"foo"})
|
||||
err := cmd.Execute()
|
||||
assert.Error(t, err)
|
||||
}
|
|
@ -9,6 +9,6 @@ var description = []string{
|
|||
var examples = [][]string{
|
||||
{
|
||||
`# Pull policy from an OCI image and save it to the specific directory`,
|
||||
`kyverno oci pull -i <imgref> -d policies`,
|
||||
`kyverno oci pull . -i <imgref>`,
|
||||
},
|
||||
}
|
||||
|
|
108
cmd/cli/kubectl-kyverno/commands/oci/pull/options.go
Normal file
108
cmd/cli/kubectl-kyverno/commands/oci/pull/options.go
Normal file
|
@ -0,0 +1,108 @@
|
|||
package pull
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
securejoin "github.com/cyphar/filepath-securejoin"
|
||||
"github.com/google/go-containerregistry/pkg/authn"
|
||||
"github.com/google/go-containerregistry/pkg/name"
|
||||
"github.com/google/go-containerregistry/pkg/v1/remote"
|
||||
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/commands/oci/internal"
|
||||
policyutils "github.com/kyverno/kyverno/pkg/utils/policy"
|
||||
yamlutils "github.com/kyverno/kyverno/pkg/utils/yaml"
|
||||
)
|
||||
|
||||
type options struct {
|
||||
imageRef string
|
||||
}
|
||||
|
||||
func (o options) validate(dir string) error {
|
||||
if o.imageRef == "" {
|
||||
return errors.New("image is required")
|
||||
}
|
||||
if dir == "" {
|
||||
return errors.New("dir is required")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o options) execute(ctx context.Context, dir string, keychain authn.Keychain) error {
|
||||
dir = filepath.Clean(dir)
|
||||
if !filepath.IsAbs(dir) {
|
||||
cwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dir, err = securejoin.SecureJoin(cwd, dir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
fi, err := os.Lstat(dir)
|
||||
// Dir does not need to exist, as it can later be created.
|
||||
if err != nil && errors.Is(err, os.ErrNotExist) {
|
||||
if err := os.MkdirAll(dir, 0o750); err != nil {
|
||||
return fmt.Errorf("unable to create directory %s: %w", dir, err)
|
||||
}
|
||||
}
|
||||
if err == nil && !fi.IsDir() {
|
||||
return fmt.Errorf("dir '%s' must be a directory", dir)
|
||||
}
|
||||
ref, err := name.ParseReference(o.imageRef)
|
||||
if err != nil {
|
||||
return fmt.Errorf("parsing image reference: %v", err)
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, "Downloading policies from an image [%s]...\n", ref.Name())
|
||||
rmt, err := remote.Get(ref, remote.WithContext(ctx), remote.WithAuthFromKeychain(keychain))
|
||||
if err != nil {
|
||||
return fmt.Errorf("getting image: %v", err)
|
||||
}
|
||||
img, err := rmt.Image()
|
||||
if err != nil {
|
||||
return fmt.Errorf("getting image: %v", err)
|
||||
}
|
||||
l, err := img.Layers()
|
||||
if err != nil {
|
||||
return fmt.Errorf("getting image layers: %v", err)
|
||||
}
|
||||
for _, layer := range l {
|
||||
lmt, err := layer.MediaType()
|
||||
if err != nil {
|
||||
return fmt.Errorf("getting layer media type: %v", err)
|
||||
}
|
||||
if lmt == internal.PolicyLayerMediaType {
|
||||
blob, err := layer.Compressed()
|
||||
if err != nil {
|
||||
return fmt.Errorf("getting layer blob: %v", err)
|
||||
}
|
||||
defer blob.Close()
|
||||
|
||||
layerBytes, err := io.ReadAll(blob)
|
||||
if err != nil {
|
||||
return fmt.Errorf("reading layer blob: %v", err)
|
||||
}
|
||||
policies, _, err := yamlutils.GetPolicy(layerBytes)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unmarshaling layer blob: %v", err)
|
||||
}
|
||||
for _, policy := range policies {
|
||||
policyBytes, err := policyutils.ToYaml(policy)
|
||||
if err != nil {
|
||||
return fmt.Errorf("converting policy to yaml: %v", err)
|
||||
}
|
||||
pp := filepath.Join(dir, policy.GetName()+".yaml")
|
||||
fmt.Fprintf(os.Stderr, "Saving policy into disk [%s]...\n", pp)
|
||||
if err := os.WriteFile(pp, policyBytes, 0o600); err != nil {
|
||||
return fmt.Errorf("creating file: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, "Done.")
|
||||
return nil
|
||||
}
|
|
@ -1,91 +1,34 @@
|
|||
package push
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"log"
|
||||
|
||||
"github.com/google/go-containerregistry/pkg/authn"
|
||||
"github.com/google/go-containerregistry/pkg/name"
|
||||
"github.com/google/go-containerregistry/pkg/v1/empty"
|
||||
"github.com/google/go-containerregistry/pkg/v1/mutate"
|
||||
"github.com/google/go-containerregistry/pkg/v1/remote"
|
||||
"github.com/google/go-containerregistry/pkg/v1/static"
|
||||
"github.com/google/go-containerregistry/pkg/v1/types"
|
||||
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/command"
|
||||
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/commands/oci/internal"
|
||||
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/log"
|
||||
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/policy"
|
||||
"github.com/kyverno/kyverno/pkg/config"
|
||||
"github.com/kyverno/kyverno/pkg/openapi"
|
||||
policyutils "github.com/kyverno/kyverno/pkg/utils/policy"
|
||||
policyvalidation "github.com/kyverno/kyverno/pkg/validation/policy"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func Command(keychain authn.Keychain) *cobra.Command {
|
||||
var policyRef string
|
||||
var imageRef string
|
||||
var options options
|
||||
cmd := &cobra.Command{
|
||||
Use: "push",
|
||||
Short: command.FormatDescription(true, websiteUrl, true, description...),
|
||||
Long: command.FormatDescription(false, websiteUrl, true, description...),
|
||||
Example: command.FormatExamples(examples...),
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if imageRef == "" {
|
||||
return errors.New("image reference is required")
|
||||
dir := args[0]
|
||||
if err := options.validate(dir); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
policies, _, err := policy.Load(nil, "", policyRef)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to read policy file or directory %s: %w", policyRef, err)
|
||||
}
|
||||
|
||||
openApiManager, err := openapi.NewManager(log.Log)
|
||||
if err != nil {
|
||||
return fmt.Errorf("creating openapi manager: %v", err)
|
||||
}
|
||||
for _, policy := range policies {
|
||||
if _, err := policyvalidation.Validate(policy, nil, nil, true, openApiManager, config.KyvernoUserName(config.KyvernoServiceAccountName())); err != nil {
|
||||
return fmt.Errorf("validating policy %s: %v", policy.GetName(), err)
|
||||
}
|
||||
}
|
||||
|
||||
img := mutate.MediaType(empty.Image, types.OCIManifestSchema1)
|
||||
img = mutate.ConfigMediaType(img, internal.PolicyConfigMediaType)
|
||||
ref, err := name.ParseReference(imageRef)
|
||||
if err != nil {
|
||||
return fmt.Errorf("parsing image reference: %v", err)
|
||||
}
|
||||
|
||||
for _, policy := range policies {
|
||||
if policy.IsNamespaced() {
|
||||
fmt.Fprintf(os.Stderr, "Adding policy [%s]\n", policy.GetName())
|
||||
} else {
|
||||
fmt.Fprintf(os.Stderr, "Adding cluster policy [%s]\n", policy.GetName())
|
||||
}
|
||||
policyBytes, err := policyutils.ToYaml(policy)
|
||||
if err != nil {
|
||||
return fmt.Errorf("converting policy to yaml: %v", err)
|
||||
}
|
||||
policyLayer := static.NewLayer(policyBytes, internal.PolicyLayerMediaType)
|
||||
img, err = mutate.Append(img, mutate.Addendum{
|
||||
Layer: policyLayer,
|
||||
Annotations: internal.Annotations(policy),
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("mutating image: %v", err)
|
||||
}
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, "Uploading [%s]...\n", ref.Name())
|
||||
if err = remote.Write(ref, img, remote.WithContext(cmd.Context()), remote.WithAuthFromKeychain(keychain)); err != nil {
|
||||
return fmt.Errorf("writing image: %v", err)
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, "Done.")
|
||||
return nil
|
||||
cmd.SilenceUsage = true
|
||||
cmd.SilenceErrors = true
|
||||
return options.execute(cmd.Context(), dir, keychain)
|
||||
},
|
||||
}
|
||||
cmd.Flags().StringVarP(&policyRef, "policy", "p", "", "path to policie(s)")
|
||||
cmd.Flags().StringVarP(&imageRef, "image", "i", "", "image reference to push to or pull from")
|
||||
cmd.Flags().StringVarP(&options.imageRef, "image", "i", "", "image reference to push to or pull from")
|
||||
if err := cmd.MarkFlagRequired("image"); err != nil {
|
||||
log.Println("WARNING", err)
|
||||
}
|
||||
return cmd
|
||||
}
|
||||
|
|
33
cmd/cli/kubectl-kyverno/commands/oci/push/command_test.go
Normal file
33
cmd/cli/kubectl-kyverno/commands/oci/push/command_test.go
Normal file
|
@ -0,0 +1,33 @@
|
|||
package push
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-containerregistry/pkg/authn"
|
||||
"github.com/google/go-containerregistry/pkg/authn/github"
|
||||
"github.com/kyverno/kyverno/pkg/registryclient"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var keychain = authn.NewMultiKeychain(
|
||||
authn.DefaultKeychain,
|
||||
github.Keychain,
|
||||
registryclient.AWSKeychain,
|
||||
registryclient.GCPKeychain,
|
||||
registryclient.AzureKeychain,
|
||||
)
|
||||
|
||||
func TestCommandNoImageRef(t *testing.T) {
|
||||
cmd := Command(keychain)
|
||||
assert.NotNil(t, cmd)
|
||||
err := cmd.Execute()
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestCommandWithArgs(t *testing.T) {
|
||||
cmd := Command(keychain)
|
||||
assert.NotNil(t, cmd)
|
||||
cmd.SetArgs([]string{"foo"})
|
||||
err := cmd.Execute()
|
||||
assert.Error(t, err)
|
||||
}
|
|
@ -9,10 +9,10 @@ var description = []string{
|
|||
var examples = [][]string{
|
||||
{
|
||||
`# Push policy to an OCI image from a given policy file`,
|
||||
`kyverno oci push -p policy.yaml -i <imgref>`,
|
||||
`kyverno oci push ./policy.yaml -i <imgref>`,
|
||||
},
|
||||
{
|
||||
`# Push multiple policies to an OCI image from a given directory that includes policies`,
|
||||
`kyverno oci push -p policies. -i <imgref>`,
|
||||
`kyverno oci push . -i <imgref>`,
|
||||
},
|
||||
}
|
||||
|
|
84
cmd/cli/kubectl-kyverno/commands/oci/push/options.go
Normal file
84
cmd/cli/kubectl-kyverno/commands/oci/push/options.go
Normal file
|
@ -0,0 +1,84 @@
|
|||
package push
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/google/go-containerregistry/pkg/authn"
|
||||
"github.com/google/go-containerregistry/pkg/name"
|
||||
"github.com/google/go-containerregistry/pkg/v1/empty"
|
||||
"github.com/google/go-containerregistry/pkg/v1/mutate"
|
||||
"github.com/google/go-containerregistry/pkg/v1/remote"
|
||||
"github.com/google/go-containerregistry/pkg/v1/static"
|
||||
"github.com/google/go-containerregistry/pkg/v1/types"
|
||||
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/commands/oci/internal"
|
||||
clilog "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/log"
|
||||
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/policy"
|
||||
"github.com/kyverno/kyverno/pkg/config"
|
||||
"github.com/kyverno/kyverno/pkg/openapi"
|
||||
policyutils "github.com/kyverno/kyverno/pkg/utils/policy"
|
||||
policyvalidation "github.com/kyverno/kyverno/pkg/validation/policy"
|
||||
)
|
||||
|
||||
type options struct {
|
||||
imageRef string
|
||||
}
|
||||
|
||||
func (o options) validate(policy string) error {
|
||||
if o.imageRef == "" {
|
||||
return errors.New("image is required")
|
||||
}
|
||||
if policy == "" {
|
||||
return errors.New("policy is required")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o options) execute(ctx context.Context, dir string, keychain authn.Keychain) error {
|
||||
policies, _, err := policy.Load(nil, "", dir)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to read policy file or directory %s (%w)", dir, err)
|
||||
}
|
||||
openApiManager, err := openapi.NewManager(clilog.Log)
|
||||
if err != nil {
|
||||
return fmt.Errorf("creating openapi manager: %v", err)
|
||||
}
|
||||
for _, policy := range policies {
|
||||
if _, err := policyvalidation.Validate(policy, nil, nil, true, openApiManager, config.KyvernoUserName(config.KyvernoServiceAccountName())); err != nil {
|
||||
return fmt.Errorf("validating policy %s: %v", policy.GetName(), err)
|
||||
}
|
||||
}
|
||||
img := mutate.MediaType(empty.Image, types.OCIManifestSchema1)
|
||||
img = mutate.ConfigMediaType(img, internal.PolicyConfigMediaType)
|
||||
ref, err := name.ParseReference(o.imageRef)
|
||||
if err != nil {
|
||||
return fmt.Errorf("parsing image reference: %v", err)
|
||||
}
|
||||
for _, policy := range policies {
|
||||
if policy.IsNamespaced() {
|
||||
fmt.Fprintf(os.Stderr, "Adding policy [%s]\n", policy.GetName())
|
||||
} else {
|
||||
fmt.Fprintf(os.Stderr, "Adding cluster policy [%s]\n", policy.GetName())
|
||||
}
|
||||
policyBytes, err := policyutils.ToYaml(policy)
|
||||
if err != nil {
|
||||
return fmt.Errorf("converting policy to yaml: %v", err)
|
||||
}
|
||||
policyLayer := static.NewLayer(policyBytes, internal.PolicyLayerMediaType)
|
||||
img, err = mutate.Append(img, mutate.Addendum{
|
||||
Layer: policyLayer,
|
||||
Annotations: internal.Annotations(policy),
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("mutating image: %v", err)
|
||||
}
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, "Uploading [%s]...\n", ref.Name())
|
||||
if err = remote.Write(ref, img, remote.WithContext(ctx), remote.WithAuthFromKeychain(keychain)); err != nil {
|
||||
return fmt.Errorf("writing image: %v", err)
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, "Done.")
|
||||
return nil
|
||||
}
|
|
@ -14,10 +14,10 @@ func Command() *cobra.Command {
|
|||
Short: command.FormatDescription(true, websiteUrl, false, description...),
|
||||
Long: command.FormatDescription(false, websiteUrl, false, description...),
|
||||
Example: command.FormatExamples(examples...),
|
||||
Args: cobra.NoArgs,
|
||||
SilenceErrors: true,
|
||||
SilenceUsage: true,
|
||||
Args: cobra.NoArgs,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
RunE: func(cmd *cobra.Command, _ []string) error {
|
||||
fmt.Fprintf(cmd.OutOrStdout(), "Version: %s\n", version.Version())
|
||||
fmt.Fprintf(cmd.OutOrStdout(), "Time: %s\n", version.Time())
|
||||
fmt.Fprintf(cmd.OutOrStdout(), "Git commit ID: %s\n", version.Hash())
|
||||
|
|
|
@ -13,6 +13,7 @@ import (
|
|||
func TestCommand(t *testing.T) {
|
||||
version.BuildVersion = "test"
|
||||
cmd := Command()
|
||||
assert.NotNil(t, cmd)
|
||||
b := bytes.NewBufferString("")
|
||||
cmd.SetOut(b)
|
||||
err := cmd.Execute()
|
||||
|
@ -28,6 +29,7 @@ Git commit ID: ---`
|
|||
|
||||
func TestCommandWithArgs(t *testing.T) {
|
||||
cmd := Command()
|
||||
assert.NotNil(t, cmd)
|
||||
cmd.SetArgs([]string{"test"})
|
||||
err := cmd.Execute()
|
||||
assert.Error(t, err)
|
||||
|
|
|
@ -9,7 +9,7 @@ Fix inconsistencies and deprecated usage in Kyverno test files.
|
|||
NOTE: This is an experimental command, use `KYVERNO_EXPERIMENTAL=true` to enable it.
|
||||
|
||||
```
|
||||
kyverno fix test [folder]... [flags]
|
||||
kyverno fix test [dir]... [flags]
|
||||
```
|
||||
|
||||
### Examples
|
||||
|
|
|
@ -11,22 +11,21 @@ Pulls policie(s) that are included in an OCI image from OCI registry and saves t
|
|||
For more information visit https://kyverno.io/docs/kyverno-cli/#pulling
|
||||
|
||||
```
|
||||
kyverno oci pull [flags]
|
||||
kyverno oci pull [dir] [flags]
|
||||
```
|
||||
|
||||
### Examples
|
||||
|
||||
```
|
||||
# Pull policy from an OCI image and save it to the specific directory
|
||||
kyverno oci pull -i <imgref> -d policies
|
||||
kyverno oci pull . -i <imgref>
|
||||
```
|
||||
|
||||
### Options
|
||||
|
||||
```
|
||||
-d, --directory string path to a directory (default ".")
|
||||
-h, --help help for pull
|
||||
-i, --image string image reference to push to or pull from
|
||||
-h, --help help for pull
|
||||
-i, --image string image reference to push to or pull from
|
||||
```
|
||||
|
||||
### Options inherited from parent commands
|
||||
|
|
|
@ -18,18 +18,17 @@ kyverno oci push [flags]
|
|||
|
||||
```
|
||||
# Push policy to an OCI image from a given policy file
|
||||
kyverno oci push -p policy.yaml -i <imgref>
|
||||
kyverno oci push ./policy.yaml -i <imgref>
|
||||
|
||||
# Push multiple policies to an OCI image from a given directory that includes policies
|
||||
kyverno oci push -p policies. -i <imgref>
|
||||
kyverno oci push . -i <imgref>
|
||||
```
|
||||
|
||||
### Options
|
||||
|
||||
```
|
||||
-h, --help help for push
|
||||
-i, --image string image reference to push to or pull from
|
||||
-p, --policy string path to policie(s)
|
||||
-h, --help help for push
|
||||
-i, --image string image reference to push to or pull from
|
||||
```
|
||||
|
||||
### Options inherited from parent commands
|
||||
|
|
|
@ -1,17 +1,19 @@
|
|||
name: karpenter-annotations-to-nodeselector
|
||||
policies:
|
||||
- policy.yaml
|
||||
- policy.yaml
|
||||
resources:
|
||||
- resource.yaml
|
||||
- resource.yaml
|
||||
results:
|
||||
- policy: karpenter-annotations-to-nodeselector
|
||||
rule: hard-nodeselector-lifecycle-on-demand
|
||||
resource: soft-pod-antiaffinity-1
|
||||
patchedResource: patched.yaml
|
||||
kind: Pod
|
||||
result: pass
|
||||
- policy: karpenter-annotations-to-nodeselector
|
||||
rule: hard-nodeselector-lifecycle-on-demand
|
||||
resource: soft-pod-antiaffinity-1-copy
|
||||
kind: Pod
|
||||
result: pass
|
||||
- kind: Pod
|
||||
patchedResource: patched.yaml
|
||||
policy: karpenter-annotations-to-nodeselector
|
||||
resources:
|
||||
- soft-pod-antiaffinity-1
|
||||
result: pass
|
||||
rule: hard-nodeselector-lifecycle-on-demand
|
||||
- kind: Pod
|
||||
policy: karpenter-annotations-to-nodeselector
|
||||
resources:
|
||||
- soft-pod-antiaffinity-1-copy
|
||||
result: pass
|
||||
rule: hard-nodeselector-lifecycle-on-demand
|
||||
|
|
Loading…
Reference in a new issue