1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-04-08 10:04:25 +00:00

Feature/CLI saving mutate results ()

* saving mutated policy and resources in yaml

* removed saving mutated policy

* fixed file creation

* updated readme

* changed flags
This commit is contained in:
Pooja Singh 2020-07-21 00:41:30 +05:30 committed by GitHub
parent 75a7543c6d
commit 47aaf50717
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 175 additions and 50 deletions
documentation
pkg
engine
kyverno/apply

View file

@ -57,7 +57,8 @@ kyverno validate /path/to/policy1.yaml /path/to/policy2.yaml /path/to/folderFull
#### Apply
Applies policies on resources, and supports applying multiple policies on multiple resources in a single command.
Also supports applying the given policies to an entire cluster. The current kubectl context will be used to access the cluster.
Will return results to stdout.
Displays mutate results to stdout, by default. Use the -o <path> flag to save mutated resources to a file or directory.
Apply to a resource:
```
@ -74,5 +75,10 @@ Apply multiple policies to multiple resources:
kyverno apply /path/to/policy1.yaml /path/to/folderFullOfPolicies --resource /path/to/resource1.yaml --resource /path/to/resource2.yaml --cluster
```
Saving the mutated resource in a file/directory:
```
kyverno apply /path/to/policy.yaml --resource /path/to/resource.yaml -o <file path/directory path>
```
<small>*Read Next >> [Sample Policies](/samples/README.md)*</small>

View file

@ -138,6 +138,7 @@ func patchedResourceHasPodControllerAnnotation(resource unstructured.Unstructure
return ok
}
func incrementAppliedRuleCount(resp *response.EngineResponse) {
resp.PolicyResponse.RulesAppliedCount++
}

View file

@ -6,6 +6,8 @@ import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strings"
"time"
client "github.com/nirmata/kyverno/pkg/dclient"
@ -42,6 +44,7 @@ func Command() *cobra.Command {
var cmd *cobra.Command
var resourcePaths []string
var cluster bool
var mutatelogPath string
kubernetesConfig := genericclioptions.NewConfigFlags(true)
@ -60,11 +63,33 @@ func Command() *cobra.Command {
}()
if len(resourcePaths) == 0 && !cluster {
return sanitizedError.NewWithError(fmt.Sprintf("resource file or cluster required"), err)
return sanitizedError.NewWithError("resource file or cluster required", err)
}
var mutatelogPathIsDir bool
if mutatelogPath != "" {
spath := strings.Split(mutatelogPath, "/")
sfileName := strings.Split(spath[len(spath)-1], ".")
if sfileName[len(sfileName)-1] == "yml" || sfileName[len(sfileName)-1] == "yaml" {
mutatelogPathIsDir = false
} else {
mutatelogPathIsDir = true
}
err = createFileOrFolder(mutatelogPath, mutatelogPathIsDir)
if err != nil {
if !sanitizedError.IsErrorSanitized(err) {
return sanitizedError.NewWithError("failed to create file/folder.", err)
}
return err
}
}
policies, openAPIController, err := common.GetPoliciesValidation(policyPaths)
if err != nil {
if !sanitizedError.IsErrorSanitized(err) {
return sanitizedError.NewWithError("failed to mutate policies.", err)
}
return err
}
@ -97,47 +122,9 @@ func Command() *cobra.Command {
return sanitizedError.NewWithError("failed to load resources", err)
}
newPolicies := make([]*v1.ClusterPolicy, 0)
logger := log.Log.WithName("apply")
for _, policy := range policies {
patches, updateMsgs := policymutation.GenerateJSONPatchesForDefaults(policy, logger)
fmt.Println("___________________________________________________________________________")
fmt.Println(updateMsgs)
type jsonPatch struct {
Path string `json:"path"`
Op string `json:"op"`
Value interface{} `json:"value"`
}
var jsonPatches []jsonPatch
err = json.Unmarshal(patches, &jsonPatches)
if err != nil {
return sanitizedError.NewWithError("failed to unmarshal patches", err)
}
patch, err := jsonpatch.DecodePatch(patches)
if err != nil {
return sanitizedError.NewWithError("failed to decode patch", err)
}
policyBytes, _ := json.Marshal(policy)
if err != nil {
return sanitizedError.NewWithError("failed to marshal policy", err)
}
modifiedPolicy, err := patch.Apply(policyBytes)
if err != nil {
return sanitizedError.NewWithError("failed to apply policy", err)
}
var p v1.ClusterPolicy
json.Unmarshal(modifiedPolicy, &p)
fmt.Printf("\nmutated %s policy after mutation:\n\n", p.Name)
yamlPolicy, _ := yamlv2.Marshal(p)
fmt.Println(string(yamlPolicy))
fmt.Println("___________________________________________________________________________")
newPolicies = append(newPolicies, &p)
newPolicies, err := mutatePolicy(policies)
if err != nil {
return sanitizedError.NewWithError("failed to mutate policy", err)
}
for i, policy := range newPolicies {
@ -146,7 +133,7 @@ func Command() *cobra.Command {
fmt.Printf("\n\n==========================================================================================\n")
}
err = applyPolicyOnResource(policy, resource)
err = applyPolicyOnResource(policy, resource, mutatelogPath, mutatelogPathIsDir)
if err != nil {
return sanitizedError.NewWithError(fmt.Errorf("failed to apply policy %v on resource %v", policy.Name, resource.GetName()).Error(), err)
}
@ -159,7 +146,7 @@ func Command() *cobra.Command {
cmd.Flags().StringArrayVarP(&resourcePaths, "resource", "r", []string{}, "Path to resource files")
cmd.Flags().BoolVarP(&cluster, "cluster", "c", false, "Checks if policies should be applied to cluster in the current context")
cmd.Flags().StringVarP(&mutatelogPath, "output", "o", "", "Prints the mutated resources in provided file/directory")
return cmd
}
@ -288,7 +275,8 @@ func getResource(path string) ([]*unstructured.Unstructured, error) {
return resources, nil
}
func applyPolicyOnResource(policy *v1.ClusterPolicy, resource *unstructured.Unstructured) error {
// applyPolicyOnResource - function to apply policy on resource
func applyPolicyOnResource(policy *v1.ClusterPolicy, resource *unstructured.Unstructured, mutatelogPath string, mutatelogPathIsDir bool) error {
fmt.Printf("\n\nApplying Policy %s on Resource %s/%s/%s\n", policy.Name, resource.GetNamespace(), resource.GetKind(), resource.GetName())
mutateResponse := engine.Mutate(engine.PolicyContext{Policy: *policy, NewResource: *resource})
@ -301,15 +289,25 @@ func applyPolicyOnResource(policy *v1.ClusterPolicy, resource *unstructured.Unst
fmt.Printf("\n\n")
} else {
if len(mutateResponse.PolicyResponse.Rules) > 0 {
fmt.Printf("\n\nMutation:")
fmt.Printf("\nMutation has been applied succesfully")
yamlEncodedResource, err := yamlv2.Marshal(mutateResponse.PatchedResource.Object)
if err != nil {
return err
}
fmt.Printf("\n\n" + string(yamlEncodedResource))
fmt.Printf("\n\n")
if mutatelogPath == "" {
fmt.Printf("\n\nMutation:\nMutation has been applied succesfully")
fmt.Printf("\n\n" + string(yamlEncodedResource))
fmt.Printf("\n\n")
} else {
err := printMutatedOutput(mutatelogPath, mutatelogPathIsDir, string(yamlEncodedResource), resource.GetName()+"-mutated")
if err != nil {
return sanitizedError.NewWithError("failed to print mutated result", err)
}
fmt.Printf("\n\nMutation:\nMutation has been applied succesfully. Check the files.")
}
} else {
fmt.Printf("\n\nMutation:\nMutation skipped. Resource not matches the policy")
}
}
@ -354,3 +352,123 @@ func applyPolicyOnResource(policy *v1.ClusterPolicy, resource *unstructured.Unst
return nil
}
// mutatePolicy - function to apply mutation on policies
func mutatePolicy(policies []*v1.ClusterPolicy) ([]*v1.ClusterPolicy, error) {
newPolicies := make([]*v1.ClusterPolicy, 0)
logger := log.Log.WithName("apply")
for _, policy := range policies {
patches, updateMsgs := policymutation.GenerateJSONPatchesForDefaults(policy, logger)
type jsonPatch struct {
Path string `json:"path"`
Op string `json:"op"`
Value interface{} `json:"value"`
}
var jsonPatches []jsonPatch
err := json.Unmarshal(patches, &jsonPatches)
if err != nil {
return nil, sanitizedError.NewWithError(fmt.Sprintf("failed to unmarshal patches for %s policy", policy.Name), err)
}
patch, err := jsonpatch.DecodePatch(patches)
if err != nil {
return nil, sanitizedError.NewWithError(fmt.Sprintf("failed to decode patch for %s policy", policy.Name), err)
}
policyBytes, _ := json.Marshal(policy)
if err != nil {
return nil, sanitizedError.NewWithError(fmt.Sprintf("failed to marshal %s policy", policy.Name), err)
}
modifiedPolicy, err := patch.Apply(policyBytes)
if err != nil {
return nil, sanitizedError.NewWithError(fmt.Sprintf("failed to apply %s policy", policy.Name), err)
}
var p v1.ClusterPolicy
json.Unmarshal(modifiedPolicy, &p)
yamlPolicy, _ := yamlv2.Marshal(p)
fmt.Println("___________________________________________________________________________")
fmt.Println(updateMsgs)
fmt.Printf("\nmutated %s policy after mutation:\n\n", p.Name)
fmt.Println(string(yamlPolicy))
fmt.Println("___________________________________________________________________________")
newPolicies = append(newPolicies, &p)
}
return newPolicies, nil
}
// printMutatedOutput - function to print output in provided file or directory
func printMutatedOutput(mutatelogPath string, mutatelogPathIsDir bool, yaml string, fileName string) error {
var f *os.File
var err error
yaml = yaml + ("\n---\n\n")
if !mutatelogPathIsDir {
f, err = os.OpenFile(mutatelogPath, os.O_APPEND|os.O_WRONLY, 0644)
} else {
f, err = os.OpenFile(mutatelogPath+"/"+fileName+".yaml", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
}
if err != nil {
return err
}
if _, err := f.Write([]byte(yaml)); err != nil {
f.Close()
return err
}
if err := f.Close(); err != nil {
return err
}
return nil
}
// createFileOrFolder - creating file or folder accoring to path provided
func createFileOrFolder(mutatelogPath string, mutatelogPathIsDir bool) error {
mutatelogPath = filepath.Clean(mutatelogPath)
_, err := os.Stat(mutatelogPath)
if err != nil {
if os.IsNotExist(err) {
if !mutatelogPathIsDir {
// check the folder existance, then create the file
s := strings.Split(mutatelogPath, "/")
folderPath := mutatelogPath[:len(mutatelogPath)-len(s[len(s)-1])-1]
_, err := os.Stat(folderPath)
fmt.Println(err)
if os.IsNotExist(err) {
errDir := os.MkdirAll(folderPath, 0755)
if errDir != nil {
return sanitizedError.NewWithError(fmt.Sprintf("failed to create directory"), err)
}
}
file, err := os.OpenFile(mutatelogPath, os.O_RDONLY|os.O_CREATE, 0644)
if err != nil {
return sanitizedError.NewWithError(fmt.Sprintf("failed to create file"), err)
}
err = file.Close()
if err != nil {
return sanitizedError.NewWithError(fmt.Sprintf("failed to close file"), err)
}
} else {
errDir := os.MkdirAll(mutatelogPath, 0755)
if errDir != nil {
return sanitizedError.NewWithError(fmt.Sprintf("failed to create directory"), err)
}
}
} else {
return sanitizedError.NewWithError(fmt.Sprintf("failed to describe file"), err)
}
}
return nil
}