mirror of
https://github.com/kyverno/kyverno.git
synced 2025-04-08 10:04:25 +00:00
Feature/CLI saving mutate results (#1007)
* saving mutated policy and resources in yaml * removed saving mutated policy * fixed file creation * updated readme * changed flags
This commit is contained in:
parent
75a7543c6d
commit
47aaf50717
3 changed files with 175 additions and 50 deletions
|
@ -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>
|
||||
|
|
|
@ -138,6 +138,7 @@ func patchedResourceHasPodControllerAnnotation(resource unstructured.Unstructure
|
|||
|
||||
return ok
|
||||
}
|
||||
|
||||
func incrementAppliedRuleCount(resp *response.EngineResponse) {
|
||||
resp.PolicyResponse.RulesAppliedCount++
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue