mirror of
https://github.com/kyverno/kyverno.git
synced 2025-03-31 03:45:17 +00:00
commit
c9cc4e271d
13 changed files with 402 additions and 20 deletions
|
@ -31,3 +31,7 @@ required = ["k8s.io/code-generator/cmd/client-gen"]
|
|||
[[override]]
|
||||
name = "github.com/golang/protobuf"
|
||||
version = "v1.2.1"
|
||||
|
||||
[[constraint]]
|
||||
name = "gopkg.in/yaml.v2"
|
||||
version = "2.2.2"
|
||||
|
|
1
cmd/build
Executable file
1
cmd/build
Executable file
|
@ -0,0 +1 @@
|
|||
go build -o kyverno
|
17
cmd/kyverno.go
Normal file
17
cmd/kyverno.go
Normal file
|
@ -0,0 +1,17 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
kyverno "github.com/nirmata/kube-policy/pkg/kyverno"
|
||||
)
|
||||
|
||||
func main() {
|
||||
cmd := kyverno.NewDefaultKyvernoCommand()
|
||||
|
||||
if err := cmd.Execute(); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "%v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
30
examples/CLI/deployment/policy-deployment.yaml
Normal file
30
examples/CLI/deployment/policy-deployment.yaml
Normal file
|
@ -0,0 +1,30 @@
|
|||
apiVersion : kubepolicy.nirmata.io/v1alpha1
|
||||
kind : Policy
|
||||
metadata :
|
||||
name : policy-deployment
|
||||
spec :
|
||||
rules:
|
||||
- name: deployment-policy
|
||||
resource:
|
||||
kind : Deployment
|
||||
selector :
|
||||
matchLabels :
|
||||
cli: test
|
||||
mutate:
|
||||
patches:
|
||||
- path: /metadata/labels/isMutated
|
||||
op: add
|
||||
value: "true"
|
||||
- path: /metadata/labels/app
|
||||
op: replace
|
||||
value: "nginx_is_mutated"
|
||||
validate:
|
||||
message: "The imagePullPolicy shoud set to Always"
|
||||
pattern:
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- (name): "*"
|
||||
imagePullPolicy: Always
|
||||
|
23
examples/CLI/deployment/resource/d1.yaml
Normal file
23
examples/CLI/deployment/resource/d1.yaml
Normal file
|
@ -0,0 +1,23 @@
|
|||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: nginx-deployment
|
||||
labels:
|
||||
app: nginx
|
||||
cli: test
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: nginx
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: nginx
|
||||
spec:
|
||||
containers:
|
||||
- name: nginx
|
||||
image: nginx:1.7.9
|
||||
imagePullPolicy: Always
|
||||
ports:
|
||||
- containerPort: 80
|
35
examples/CLI/deployment/resource/d2.yaml
Normal file
35
examples/CLI/deployment/resource/d2.yaml
Normal file
|
@ -0,0 +1,35 @@
|
|||
kind: "Deployment"
|
||||
apiVersion: "extensions/v1beta1"
|
||||
metadata:
|
||||
name: "ghost"
|
||||
labels:
|
||||
nirmata.io/deployment.name: "ghost"
|
||||
nirmata.io/application.name: "ghost"
|
||||
nirmata.io/component: "ghost"
|
||||
cli: test
|
||||
spec:
|
||||
replicas: 1
|
||||
revisionHistoryLimit: 5
|
||||
selector:
|
||||
matchLabels:
|
||||
nirmata.io/application.name: "ghost"
|
||||
nirmata.io/component: "ghost"
|
||||
strategy:
|
||||
type: "RollingUpdate"
|
||||
rollingUpdate:
|
||||
maxSurge: 1
|
||||
maxUnavailable: 0
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
nirmata.io/deployment.name: "ghost"
|
||||
nirmata.io/application.name: "ghost"
|
||||
nirmata.io/component: "ghost"
|
||||
spec:
|
||||
containers:
|
||||
- name: "ghost"
|
||||
image: "ghost:2.9.1-alpine"
|
||||
imagePullPolicy: Always
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
protocol: "TCP"
|
|
@ -10,8 +10,11 @@ import (
|
|||
|
||||
// Mutate performs mutation. Overlay first and then mutation patches
|
||||
// TODO: return events and violations
|
||||
func Mutate(policy kubepolicy.Policy, rawResource []byte, gvk metav1.GroupVersionKind) []mutation.PatchBytes {
|
||||
func Mutate(policy kubepolicy.Policy, rawResource []byte, gvk metav1.GroupVersionKind) ([]mutation.PatchBytes, []byte) {
|
||||
var policyPatches []mutation.PatchBytes
|
||||
var processedPatches []mutation.PatchBytes
|
||||
var err error
|
||||
patchedDocument := rawResource
|
||||
|
||||
for _, rule := range policy.Spec.Rules {
|
||||
if rule.Mutation == nil {
|
||||
|
@ -38,7 +41,7 @@ func Mutate(policy kubepolicy.Policy, rawResource []byte, gvk metav1.GroupVersio
|
|||
// Process Patches
|
||||
|
||||
if rule.Mutation.Patches != nil {
|
||||
processedPatches, err := mutation.ProcessPatches(rule.Mutation.Patches, rawResource)
|
||||
processedPatches, patchedDocument, err = mutation.ProcessPatches(rule.Mutation.Patches, patchedDocument)
|
||||
if err != nil {
|
||||
log.Printf("Patches application has failed for rule %s in policy %s, err: %v\n", rule.Name, policy.ObjectMeta.Name, err)
|
||||
} else {
|
||||
|
@ -47,5 +50,5 @@ func Mutate(policy kubepolicy.Policy, rawResource []byte, gvk metav1.GroupVersio
|
|||
}
|
||||
}
|
||||
|
||||
return policyPatches
|
||||
return policyPatches, patchedDocument
|
||||
}
|
||||
|
|
|
@ -13,28 +13,32 @@ type PatchBytes []byte
|
|||
|
||||
// ProcessPatches Returns array from separate patches that can be applied to the document
|
||||
// Returns error ONLY in case when creation of resource should be denied.
|
||||
func ProcessPatches(patches []kubepolicy.Patch, resource []byte) ([]PatchBytes, error) {
|
||||
func ProcessPatches(patches []kubepolicy.Patch, resource []byte) ([]PatchBytes, []byte, error) {
|
||||
if len(resource) == 0 {
|
||||
return nil, errors.New("Source document for patching is empty")
|
||||
return nil, nil, errors.New("Source document for patching is empty")
|
||||
}
|
||||
|
||||
var appliedPatches []PatchBytes
|
||||
patchedDocument := resource
|
||||
for i, patch := range patches {
|
||||
patchRaw, err := json.Marshal(patch)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
_, err = applyPatch(resource, patchRaw)
|
||||
patchedDocument, err = applyPatch(patchedDocument, patchRaw)
|
||||
if err != nil {
|
||||
// TODO: continue on error if one of the patches fails, will add the failure event in such case
|
||||
if patch.Operation == "remove" {
|
||||
continue
|
||||
}
|
||||
log.Printf("Patch failed: patch number = %d, patch Operation = %s, err: %v", i, patch.Operation, err)
|
||||
continue
|
||||
}
|
||||
|
||||
appliedPatches = append(appliedPatches, patchRaw)
|
||||
}
|
||||
return appliedPatches, nil
|
||||
return appliedPatches, patchedDocument, nil
|
||||
}
|
||||
|
||||
// JoinPatches joins array of serialized JSON patches to the single JSONPatch array
|
||||
|
@ -65,5 +69,9 @@ func applyPatch(resource []byte, patchRaw []byte) ([]byte, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
return patch.Apply(resource)
|
||||
patchedDocument, err := patch.Apply(resource)
|
||||
if err != nil {
|
||||
return resource, err
|
||||
}
|
||||
return patchedDocument, err
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ const endpointsDocument string = `{
|
|||
|
||||
func TestProcessPatches_EmptyPatches(t *testing.T) {
|
||||
var empty []types.Patch
|
||||
patches, err := ProcessPatches(empty, []byte(endpointsDocument))
|
||||
patches, _, err := ProcessPatches(empty, []byte(endpointsDocument))
|
||||
assert.NilError(t, err)
|
||||
assert.Assert(t, len(patches) == 0)
|
||||
}
|
||||
|
@ -51,13 +51,13 @@ func makeAddIsMutatedLabelPatch() types.Patch {
|
|||
func TestProcessPatches_EmptyDocument(t *testing.T) {
|
||||
var patches []types.Patch
|
||||
patches = append(patches, makeAddIsMutatedLabelPatch())
|
||||
patchesBytes, err := ProcessPatches(patches, nil)
|
||||
patchesBytes, _, err := ProcessPatches(patches, nil)
|
||||
assert.Assert(t, err != nil)
|
||||
assert.Assert(t, len(patchesBytes) == 0)
|
||||
}
|
||||
|
||||
func TestProcessPatches_AllEmpty(t *testing.T) {
|
||||
patchesBytes, err := ProcessPatches(nil, nil)
|
||||
patchesBytes, _, err := ProcessPatches(nil, nil)
|
||||
assert.Assert(t, err != nil)
|
||||
assert.Assert(t, len(patchesBytes) == 0)
|
||||
}
|
||||
|
@ -66,7 +66,7 @@ func TestProcessPatches_AddPathDoesntExist(t *testing.T) {
|
|||
patch := makeAddIsMutatedLabelPatch()
|
||||
patch.Path = "/metadata/additional/is-mutated"
|
||||
patches := []types.Patch{patch}
|
||||
patchesBytes, err := ProcessPatches(patches, []byte(endpointsDocument))
|
||||
patchesBytes, _, err := ProcessPatches(patches, []byte(endpointsDocument))
|
||||
assert.NilError(t, err)
|
||||
assert.Assert(t, len(patchesBytes) == 0)
|
||||
}
|
||||
|
@ -74,7 +74,7 @@ func TestProcessPatches_AddPathDoesntExist(t *testing.T) {
|
|||
func TestProcessPatches_RemovePathDoesntExist(t *testing.T) {
|
||||
patch := types.Patch{Path: "/metadata/labels/is-mutated", Operation: "remove"}
|
||||
patches := []types.Patch{patch}
|
||||
patchesBytes, err := ProcessPatches(patches, []byte(endpointsDocument))
|
||||
patchesBytes, _, err := ProcessPatches(patches, []byte(endpointsDocument))
|
||||
assert.NilError(t, err)
|
||||
assert.Assert(t, len(patchesBytes) == 0)
|
||||
}
|
||||
|
@ -83,7 +83,7 @@ func TestProcessPatches_AddAndRemovePathsDontExist_EmptyResult(t *testing.T) {
|
|||
patch1 := types.Patch{Path: "/metadata/labels/is-mutated", Operation: "remove"}
|
||||
patch2 := types.Patch{Path: "/spec/labels/label3", Operation: "add", Value: "label3Value"}
|
||||
patches := []types.Patch{patch1, patch2}
|
||||
patchesBytes, err := ProcessPatches(patches, []byte(endpointsDocument))
|
||||
patchesBytes, _, err := ProcessPatches(patches, []byte(endpointsDocument))
|
||||
assert.NilError(t, err)
|
||||
assert.Assert(t, len(patchesBytes) == 0)
|
||||
}
|
||||
|
@ -93,7 +93,7 @@ func TestProcessPatches_AddAndRemovePathsDontExist_ContinueOnError_NotEmptyResul
|
|||
patch2 := types.Patch{Path: "/spec/labels/label2", Operation: "remove", Value: "label2Value"}
|
||||
patch3 := types.Patch{Path: "/metadata/labels/label3", Operation: "add", Value: "label3Value"}
|
||||
patches := []types.Patch{patch1, patch2, patch3}
|
||||
patchesBytes, err := ProcessPatches(patches, []byte(endpointsDocument))
|
||||
patchesBytes, _, err := ProcessPatches(patches, []byte(endpointsDocument))
|
||||
assert.NilError(t, err)
|
||||
assert.Assert(t, len(patchesBytes) == 1)
|
||||
assertEqStringAndData(t, `{"path":"/metadata/labels/label3","op":"add","value":"label3Value"}`, patchesBytes[0])
|
||||
|
@ -102,7 +102,7 @@ func TestProcessPatches_AddAndRemovePathsDontExist_ContinueOnError_NotEmptyResul
|
|||
func TestProcessPatches_RemovePathDoesntExist_EmptyResult(t *testing.T) {
|
||||
patch := types.Patch{Path: "/metadata/labels/is-mutated", Operation: "remove"}
|
||||
patches := []types.Patch{patch}
|
||||
patchesBytes, err := ProcessPatches(patches, []byte(endpointsDocument))
|
||||
patchesBytes, _, err := ProcessPatches(patches, []byte(endpointsDocument))
|
||||
assert.NilError(t, err)
|
||||
assert.Assert(t, len(patchesBytes) == 0)
|
||||
}
|
||||
|
@ -111,7 +111,7 @@ func TestProcessPatches_RemovePathDoesntExist_NotEmptyResult(t *testing.T) {
|
|||
patch1 := types.Patch{Path: "/metadata/labels/is-mutated", Operation: "remove"}
|
||||
patch2 := types.Patch{Path: "/metadata/labels/label2", Operation: "add", Value: "label2Value"}
|
||||
patches := []types.Patch{patch1, patch2}
|
||||
patchesBytes, err := ProcessPatches(patches, []byte(endpointsDocument))
|
||||
patchesBytes, _, err := ProcessPatches(patches, []byte(endpointsDocument))
|
||||
assert.NilError(t, err)
|
||||
assert.Assert(t, len(patchesBytes) == 1)
|
||||
assertEqStringAndData(t, `{"path":"/metadata/labels/label2","op":"add","value":"label2Value"}`, patchesBytes[0])
|
||||
|
|
|
@ -56,7 +56,6 @@ func Validate(policy kubepolicy.Policy, rawResource []byte, gvk metav1.GroupVers
|
|||
}
|
||||
}
|
||||
|
||||
log.Println("Validation is successful")
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
237
pkg/kyverno/apply/apply.go
Normal file
237
pkg/kyverno/apply/apply.go
Normal file
|
@ -0,0 +1,237 @@
|
|||
package apply
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
kubepolicy "github.com/nirmata/kube-policy/pkg/apis/policy/v1alpha1"
|
||||
"github.com/nirmata/kube-policy/pkg/engine"
|
||||
"github.com/spf13/cobra"
|
||||
yamlv2 "gopkg.in/yaml.v2"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
yaml "k8s.io/apimachinery/pkg/util/yaml"
|
||||
)
|
||||
|
||||
const applyExample = ` # Apply a policy to the resource.
|
||||
kyverno apply @policy.yaml @resource.yaml
|
||||
kyverno apply @policy.yaml @resourceDir/`
|
||||
|
||||
// NewCmdApply returns the apply command for kyverno
|
||||
func NewCmdApply(in io.Reader, out, errout io.Writer) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "apply",
|
||||
Short: "Apply policy on the resource(s)",
|
||||
Example: applyExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
var output string
|
||||
policy, resources := complete(args)
|
||||
|
||||
for _, resource := range resources {
|
||||
patchedDocument, err := applyPolicy(policy, resource.rawResource, resource.gvk)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
out, err := prettyPrint(patchedDocument)
|
||||
if err != nil {
|
||||
fmt.Printf("JSON parse error: %v\n", err)
|
||||
fmt.Printf("%v\n", string(patchedDocument))
|
||||
return
|
||||
}
|
||||
|
||||
output = output + fmt.Sprintf("---\n%s", string(out))
|
||||
}
|
||||
fmt.Printf("%v\n", output)
|
||||
},
|
||||
}
|
||||
return cmd
|
||||
}
|
||||
|
||||
func complete(args []string) (*kubepolicy.Policy, []*resourceInfo) {
|
||||
|
||||
policyDir, resourceDir, err := validateDir(args)
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to parse file path, err: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// extract policy
|
||||
policy, err := extractPolicy(policyDir)
|
||||
if err != nil {
|
||||
log.Printf("failed to extract policy: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// extract rawResource
|
||||
resources, err := extractResource(resourceDir)
|
||||
if err != nil {
|
||||
log.Printf("failed to parse resource: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
return policy, resources
|
||||
}
|
||||
|
||||
func applyPolicy(policy *kubepolicy.Policy, rawResource []byte, gvk *metav1.GroupVersionKind) ([]byte, error) {
|
||||
_, patchedDocument := engine.Mutate(*policy, rawResource, *gvk)
|
||||
|
||||
if err := engine.Validate(*policy, rawResource, *gvk); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return patchedDocument, nil
|
||||
}
|
||||
|
||||
func extractPolicy(fileDir string) (*kubepolicy.Policy, error) {
|
||||
policy := &kubepolicy.Policy{}
|
||||
|
||||
file, err := loadFile(fileDir)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to load file: %v", err)
|
||||
}
|
||||
|
||||
policyBytes, err := yaml.ToJSON(file)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(policyBytes, policy); err != nil {
|
||||
return nil, fmt.Errorf("failed to decode policy %s, err: %v", policy.Name, err)
|
||||
}
|
||||
|
||||
if policy.TypeMeta.Kind != "Policy" {
|
||||
return nil, fmt.Errorf("failed to parse policy")
|
||||
}
|
||||
|
||||
return policy, nil
|
||||
}
|
||||
|
||||
type resourceInfo struct {
|
||||
rawResource []byte
|
||||
gvk *metav1.GroupVersionKind
|
||||
}
|
||||
|
||||
func extractResource(fileDir string) ([]*resourceInfo, error) {
|
||||
var files []string
|
||||
var resources []*resourceInfo
|
||||
// check if applied on multiple resources
|
||||
isDir, err := isDir(fileDir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if isDir {
|
||||
files, err = ScanDir(fileDir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
files = []string{fileDir}
|
||||
}
|
||||
|
||||
for _, dir := range files {
|
||||
file, err := loadFile(dir)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to load file: %v", err)
|
||||
}
|
||||
|
||||
data := make(map[interface{}]interface{})
|
||||
|
||||
if err = yamlv2.Unmarshal([]byte(file), &data); err != nil {
|
||||
return nil, fmt.Errorf("failed to parse resource: %v", err)
|
||||
}
|
||||
|
||||
apiVersion, ok := data["apiVersion"].(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("failed to parse apiversion: %v", err)
|
||||
}
|
||||
|
||||
kind, ok := data["kind"].(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("failed to parse kind of resource: %v", err)
|
||||
}
|
||||
|
||||
var gvkInfo *metav1.GroupVersionKind
|
||||
gv := strings.Split(apiVersion, "/")
|
||||
if len(gv) == 2 {
|
||||
gvkInfo = &metav1.GroupVersionKind{Group: gv[0], Version: gv[1], Kind: kind}
|
||||
} else {
|
||||
gvkInfo = &metav1.GroupVersionKind{Version: gv[0], Kind: kind}
|
||||
}
|
||||
|
||||
json, err := yaml.ToJSON(file)
|
||||
|
||||
resources = append(resources, &resourceInfo{rawResource: json, gvk: gvkInfo})
|
||||
}
|
||||
|
||||
return resources, err
|
||||
}
|
||||
|
||||
func loadFile(fileDir string) ([]byte, error) {
|
||||
if _, err := os.Stat(fileDir); os.IsNotExist(err) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return ioutil.ReadFile(fileDir)
|
||||
}
|
||||
|
||||
func validateDir(args []string) (policyDir, resourceDir string, err error) {
|
||||
if len(args) != 2 {
|
||||
return "", "", fmt.Errorf("missing policy and/or resource manifest")
|
||||
}
|
||||
|
||||
if strings.HasPrefix(args[0], "@") {
|
||||
policyDir = args[0][1:]
|
||||
}
|
||||
|
||||
if strings.HasPrefix(args[1], "@") {
|
||||
resourceDir = args[1][1:]
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func prettyPrint(data []byte) ([]byte, error) {
|
||||
out := make(map[interface{}]interface{})
|
||||
if err := yamlv2.Unmarshal(data, &out); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return yamlv2.Marshal(&out)
|
||||
}
|
||||
|
||||
func isDir(dir string) (bool, error) {
|
||||
fi, err := os.Stat(dir)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return fi.IsDir(), nil
|
||||
}
|
||||
|
||||
func ScanDir(dir string) ([]string, error) {
|
||||
var res []string
|
||||
|
||||
err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
fmt.Printf("prevent panic by handling failure accessing a path %q: %v\n", dir, err)
|
||||
return err
|
||||
}
|
||||
/* if len(strings.Split(path, "/")) == 4 {
|
||||
fmt.Println(path)
|
||||
} */
|
||||
res = append(res, path)
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error walking the path %q: %v", dir, err)
|
||||
}
|
||||
|
||||
return res[1:], nil
|
||||
}
|
25
pkg/kyverno/cmd.go
Normal file
25
pkg/kyverno/cmd.go
Normal file
|
@ -0,0 +1,25 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/nirmata/kube-policy/pkg/kyverno/apply"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// NewDefaultKyvernoCommand ...
|
||||
func NewDefaultKyvernoCommand() *cobra.Command {
|
||||
return NewKyvernoCommand(os.Stdin, os.Stdout, os.Stderr)
|
||||
}
|
||||
|
||||
// NewKyvernoCommand returns the new kynerno command
|
||||
func NewKyvernoCommand(in io.Reader, out, errout io.Writer) *cobra.Command {
|
||||
cmds := &cobra.Command{
|
||||
Use: "kyverno",
|
||||
Short: "kyverno manages native policies of Kubernetes",
|
||||
}
|
||||
|
||||
cmds.AddCommand(apply.NewCmdApply(in, out, errout))
|
||||
return cmds
|
||||
}
|
|
@ -147,7 +147,7 @@ func (ws *WebhookServer) HandleMutation(request *v1beta1.AdmissionRequest) *v1be
|
|||
for _, policy := range policies {
|
||||
ws.logger.Printf("Applying policy %s with %d rules\n", policy.ObjectMeta.Name, len(policy.Spec.Rules))
|
||||
|
||||
policyPatches := engine.Mutate(*policy, request.Object.Raw, request.Kind)
|
||||
policyPatches, _ := engine.Mutate(*policy, request.Object.Raw, request.Kind)
|
||||
allPatches = append(allPatches, policyPatches...)
|
||||
|
||||
if len(policyPatches) > 0 {
|
||||
|
|
Loading…
Add table
Reference in a new issue