mirror of
https://github.com/kyverno/kyverno.git
synced 2025-03-13 19:28:55 +00:00
feat: add create exception cli command (#7781)
Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>
This commit is contained in:
parent
045e955a6e
commit
a1d06b41df
10 changed files with 390 additions and 3 deletions
|
@ -2,6 +2,7 @@ package create
|
|||
|
||||
import (
|
||||
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/command"
|
||||
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/commands/create/exception"
|
||||
metricsconfig "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/commands/create/metrics-config"
|
||||
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/commands/create/test"
|
||||
userinfo "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/commands/create/user-info"
|
||||
|
@ -20,6 +21,7 @@ func Command() *cobra.Command {
|
|||
},
|
||||
}
|
||||
cmd.AddCommand(
|
||||
exception.Command(),
|
||||
metricsconfig.Command(),
|
||||
test.Command(),
|
||||
userinfo.Command(),
|
||||
|
|
117
cmd/cli/kubectl-kyverno/commands/create/exception/command.go
Normal file
117
cmd/cli/kubectl-kyverno/commands/create/exception/command.go
Normal file
|
@ -0,0 +1,117 @@
|
|||
package exception
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
|
||||
"github.com/kyverno/kyverno/api/kyverno/v2alpha1"
|
||||
"github.com/kyverno/kyverno/api/kyverno/v2beta1"
|
||||
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/command"
|
||||
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/commands/create/templates"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
type options struct {
|
||||
Name string
|
||||
Namespace string
|
||||
Background bool
|
||||
Exceptions []v2alpha1.Exception
|
||||
Match v2beta1.MatchResources
|
||||
}
|
||||
|
||||
func Command() *cobra.Command {
|
||||
var path string
|
||||
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),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
tmpl, err := template.New("exception").Parse(templates.ExceptionTemplate)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
options.Name = args[0]
|
||||
for _, result := range rules {
|
||||
result := parseRule(result)
|
||||
if result != nil {
|
||||
options.Exceptions = append(options.Exceptions, *result)
|
||||
}
|
||||
}
|
||||
for _, result := range any {
|
||||
result := parseResourceFilter(result)
|
||||
if result != nil {
|
||||
options.Match.Any = append(options.Match.Any, *result)
|
||||
}
|
||||
}
|
||||
for _, result := range all {
|
||||
result := parseResourceFilter(result)
|
||||
if result != nil {
|
||||
options.Match.All = append(options.Match.All, *result)
|
||||
}
|
||||
}
|
||||
output := cmd.OutOrStdout()
|
||||
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().StringVar(&options.Namespace, "namespace", "", "Policy exception namespace")
|
||||
cmd.Flags().BoolVarP(&options.Background, "background", "b", true, "Set to false when policy shouldn't be considered in background scans")
|
||||
cmd.Flags().StringArrayVar(&rules, "policy-rules", nil, "Policy name, followed by rule names (`--policy-rules=policy,rule-1,rule-2,...`)")
|
||||
cmd.Flags().StringArrayVar(&any, "any", nil, "List of resource filters")
|
||||
cmd.Flags().StringArrayVar(&all, "all", nil, "List of resource filters")
|
||||
if err := cmd.MarkFlagRequired("policy-rules"); err != nil {
|
||||
log.Println("WARNING", err)
|
||||
}
|
||||
return cmd
|
||||
}
|
||||
|
||||
func parseRule(in string) *v2alpha1.Exception {
|
||||
parts := strings.Split(in, ",")
|
||||
if len(parts) < 2 {
|
||||
return nil
|
||||
}
|
||||
return &v2alpha1.Exception{
|
||||
PolicyName: parts[0],
|
||||
RuleNames: parts[1:],
|
||||
}
|
||||
}
|
||||
|
||||
func parseResourceFilter(in string) *kyvernov1.ResourceFilter {
|
||||
parts := strings.Split(in, ",")
|
||||
if len(parts) == 0 {
|
||||
return nil
|
||||
}
|
||||
var result kyvernov1.ResourceFilter
|
||||
for _, part := range parts {
|
||||
kv := strings.Split(part, "=")
|
||||
if len(kv) != 2 {
|
||||
return nil
|
||||
}
|
||||
switch kv[0] {
|
||||
case "kind":
|
||||
result.Kinds = append(result.Kinds, kv[1])
|
||||
case "name":
|
||||
result.Names = append(result.Names, kv[1])
|
||||
case "namespace":
|
||||
result.Namespaces = append(result.Namespaces, kv[1])
|
||||
case "operation":
|
||||
result.Operations = append(result.Operations, kyvernov1.AdmissionOperation(kv[1]))
|
||||
}
|
||||
}
|
||||
return &result
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
package exception
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestCommand(t *testing.T) {
|
||||
cmd := Command()
|
||||
cmd.SetArgs([]string{"test", "--policy-rules", "policy,rule-1,rule-2"})
|
||||
err := cmd.Execute()
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestCommandWithMultipleArgs(t *testing.T) {
|
||||
cmd := Command()
|
||||
cmd.SetArgs([]string{"test", "test2", "--policy-rules", "policy,rule-1,rule-2"})
|
||||
err := cmd.Execute()
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestCommandWithoutPolicyRules(t *testing.T) {
|
||||
cmd := Command()
|
||||
cmd.SetArgs([]string{"test", "test2"})
|
||||
err := cmd.Execute()
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestCommandWithAny(t *testing.T) {
|
||||
cmd := Command()
|
||||
cmd.SetArgs([]string{"test", "--policy-rules", "policy,rule-1,rule-2", "--any", "kind=Pod,kind=Deployment,name=test-*"})
|
||||
b := bytes.NewBufferString("")
|
||||
cmd.SetOut(b)
|
||||
err := cmd.Execute()
|
||||
assert.NoError(t, err)
|
||||
out, err := io.ReadAll(b)
|
||||
assert.NoError(t, err)
|
||||
expected := `
|
||||
apiVersion: kyverno.io/v2alpha1
|
||||
kind: PolicyException
|
||||
metadata:
|
||||
name: test
|
||||
namespace:
|
||||
spec:
|
||||
background: true
|
||||
match:
|
||||
any:
|
||||
-
|
||||
kinds:
|
||||
- Pod
|
||||
- Deployment
|
||||
names:
|
||||
- test-*
|
||||
exceptions:
|
||||
- policyName: policy
|
||||
ruleNames:
|
||||
- rule-1
|
||||
- rule-2`
|
||||
assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(string(out)))
|
||||
}
|
||||
|
||||
func TestCommandWithAll(t *testing.T) {
|
||||
cmd := Command()
|
||||
cmd.SetArgs([]string{"test", "--policy-rules", "policy,rule-1,rule-2", "--all", "kind=Pod,kind=Deployment,name=test-*,namespace=test,operation=UPDATE"})
|
||||
b := bytes.NewBufferString("")
|
||||
cmd.SetOut(b)
|
||||
err := cmd.Execute()
|
||||
assert.NoError(t, err)
|
||||
out, err := io.ReadAll(b)
|
||||
assert.NoError(t, err)
|
||||
expected := `
|
||||
apiVersion: kyverno.io/v2alpha1
|
||||
kind: PolicyException
|
||||
metadata:
|
||||
name: test
|
||||
namespace:
|
||||
spec:
|
||||
background: true
|
||||
match:
|
||||
all:
|
||||
-
|
||||
kinds:
|
||||
- Pod
|
||||
- Deployment
|
||||
names:
|
||||
- test-*
|
||||
namespaces:
|
||||
- test
|
||||
operations:
|
||||
- UPDATE
|
||||
exceptions:
|
||||
- policyName: policy
|
||||
ruleNames:
|
||||
- rule-1
|
||||
- rule-2`
|
||||
assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(string(out)))
|
||||
}
|
15
cmd/cli/kubectl-kyverno/commands/create/exception/doc.go
Normal file
15
cmd/cli/kubectl-kyverno/commands/create/exception/doc.go
Normal file
|
@ -0,0 +1,15 @@
|
|||
package exception
|
||||
|
||||
// TODO
|
||||
var websiteUrl = ``
|
||||
|
||||
var description = []string{
|
||||
`Create a Kyverno policy exception file.`,
|
||||
}
|
||||
|
||||
var examples = [][]string{
|
||||
{
|
||||
"# Create a policy exception file",
|
||||
`kyverno create exception my-exception --namespace my-ns --policy-rules "policy,rule-1,rule-2" --any "kind=Pod,kind=Deployment,name=test-*"`,
|
||||
},
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
apiVersion: kyverno.io/v2alpha1
|
||||
kind: PolicyException
|
||||
metadata:
|
||||
name: {{ .Name }}
|
||||
namespace: {{ .Namespace }}
|
||||
spec:
|
||||
background: {{ .Background }}
|
||||
match:
|
||||
|
||||
{{- with .Match.Any }}
|
||||
any:
|
||||
{{- range . }}
|
||||
-
|
||||
{{- with .Kinds }}
|
||||
kinds:
|
||||
{{- range . }}
|
||||
- {{ . }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- with .Names }}
|
||||
names:
|
||||
{{- range . }}
|
||||
- {{ . }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- with .Namespaces }}
|
||||
namespaces:
|
||||
{{- range . }}
|
||||
- {{ . }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- with .Operations }}
|
||||
operations:
|
||||
{{- range . }}
|
||||
- {{ . }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{- with .Match.All }}
|
||||
all:
|
||||
{{- range . }}
|
||||
-
|
||||
{{- with .Kinds }}
|
||||
kinds:
|
||||
{{- range . }}
|
||||
- {{ . }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- with .Names }}
|
||||
names:
|
||||
{{- range . }}
|
||||
- {{ . }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- with .Namespaces }}
|
||||
namespaces:
|
||||
{{- range . }}
|
||||
- {{ . }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- with .Operations }}
|
||||
operations:
|
||||
{{- range . }}
|
||||
- {{ . }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{- with .Exceptions }}
|
||||
exceptions:
|
||||
{{- range . }}
|
||||
- policyName: {{ .PolicyName }}
|
||||
ruleNames:
|
||||
{{- range .RuleNames }}
|
||||
- {{ . }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
|
@ -13,5 +13,8 @@ var ValuesTemplate string
|
|||
//go:embed user-info.yaml
|
||||
var UserInfoTemplate string
|
||||
|
||||
//go:embed exception.yaml
|
||||
var ExceptionTemplate string
|
||||
|
||||
//go:embed metrics-config.yaml
|
||||
var MetricsConfigTemplate string
|
||||
|
|
|
@ -16,9 +16,9 @@ func Command() *cobra.Command {
|
|||
Example: command.FormatExamples(examples...),
|
||||
Args: cobra.NoArgs,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
fmt.Printf("Version: %s\n", version.Version())
|
||||
fmt.Printf("Time: %s\n", version.Time())
|
||||
fmt.Printf("Git commit ID: %s\n", version.Hash())
|
||||
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())
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
|
|
@ -1,15 +1,29 @@
|
|||
package version
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/kyverno/kyverno/pkg/version"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestCommand(t *testing.T) {
|
||||
version.BuildVersion = "test"
|
||||
cmd := Command()
|
||||
b := bytes.NewBufferString("")
|
||||
cmd.SetOut(b)
|
||||
err := cmd.Execute()
|
||||
assert.NoError(t, err)
|
||||
out, err := io.ReadAll(b)
|
||||
assert.NoError(t, err)
|
||||
expected := `
|
||||
Version: test
|
||||
Time: ---
|
||||
Git commit ID: ---`
|
||||
assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(string(out)))
|
||||
}
|
||||
|
||||
func TestCommandWithArgs(t *testing.T) {
|
||||
|
|
|
@ -53,6 +53,7 @@ kyverno create [flags]
|
|||
### SEE ALSO
|
||||
|
||||
* [kyverno](kyverno.md) - Kubernetes Native Policy Management.
|
||||
* [kyverno create exception](kyverno_create_exception.md) - Create a Kyverno policy exception file.
|
||||
* [kyverno create metrics-config](kyverno_create_metrics-config.md) - Create a Kyverno metrics-config file.
|
||||
* [kyverno create test](kyverno_create_test.md) - Create a Kyverno test file.
|
||||
* [kyverno create user-info](kyverno_create_user-info.md) - Create a Kyverno user-info file.
|
||||
|
|
53
docs/user/cli/kyverno_create_exception.md
Normal file
53
docs/user/cli/kyverno_create_exception.md
Normal file
|
@ -0,0 +1,53 @@
|
|||
## kyverno create exception
|
||||
|
||||
Create a Kyverno policy exception file.
|
||||
|
||||
### Synopsis
|
||||
|
||||
Create a Kyverno policy exception file.
|
||||
|
||||
```
|
||||
kyverno create exception [name] [flags]
|
||||
```
|
||||
|
||||
### Examples
|
||||
|
||||
```
|
||||
# Create a policy exception file
|
||||
kyverno create exception my-exception --namespace my-ns --policy-rules "policy,rule-1,rule-2" --any "kind=Pod,kind=Deployment,name=test-*"
|
||||
```
|
||||
|
||||
### Options
|
||||
|
||||
```
|
||||
--all stringArray List of resource filters
|
||||
--any stringArray List of resource filters
|
||||
-b, --background Set to false when policy shouldn't be considered in background scans (default true)
|
||||
-h, --help help for exception
|
||||
--namespace string Policy exception namespace
|
||||
-o, --output string Output path (uses standard console output if not set)
|
||||
--policy-rules --policy-rules=policy,rule-1,rule-2,... Policy name, followed by rule names (--policy-rules=policy,rule-1,rule-2,...)
|
||||
```
|
||||
|
||||
### Options inherited from parent commands
|
||||
|
||||
```
|
||||
--add_dir_header If true, adds the file directory to the header of the log messages
|
||||
--alsologtostderr log to standard error as well as files (no effect when -logtostderr=true)
|
||||
--log_backtrace_at traceLocation when logging hits line file:N, emit a stack trace (default :0)
|
||||
--log_dir string If non-empty, write log files in this directory (no effect when -logtostderr=true)
|
||||
--log_file string If non-empty, use this log file (no effect when -logtostderr=true)
|
||||
--log_file_max_size uint Defines the maximum size a log file can grow to (no effect when -logtostderr=true). Unit is megabytes. If the value is 0, the maximum file size is unlimited. (default 1800)
|
||||
--logtostderr log to standard error instead of files (default true)
|
||||
--one_output If true, only write logs to their native severity level (vs also writing to each lower severity level; no effect when -logtostderr=true)
|
||||
--skip_headers If true, avoid header prefixes in the log messages
|
||||
--skip_log_headers If true, avoid headers when opening log files (no effect when -logtostderr=true)
|
||||
--stderrthreshold severity logs at or above this threshold go to stderr when writing to files and stderr (no effect when -logtostderr=true or -alsologtostderr=false) (default 2)
|
||||
-v, --v Level number for the log level verbosity
|
||||
--vmodule moduleSpec comma-separated list of pattern=N settings for file-filtered logging
|
||||
```
|
||||
|
||||
### SEE ALSO
|
||||
|
||||
* [kyverno create](kyverno_create.md) - Helps with the creation of various Kyverno resources.
|
||||
|
Loading…
Add table
Reference in a new issue