Skip to content

Commit

Permalink
Print generate output cli (kyverno#11634)
Browse files Browse the repository at this point in the history
* refactor: Configure the policy processor to print generated resources

Refactor printMutatedOutput to printOutput which prints mutate or generate resources to a file or standard output
Introduce processGenerateResponse which extracts generated resources from the policy response and passes them to printOutput

Signed-off-by: aerosouund <[email protected]>

* chore: Update flag description to specify mutated and generated resources

Signed-off-by: aerosouund <[email protected]>

* chore: Run codegen

Signed-off-by: aerosouund <[email protected]>

---------

Signed-off-by: aerosouund <[email protected]>
  • Loading branch information
aerosouund authored Nov 27, 2024
1 parent 88306bb commit d100202
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 30 deletions.
2 changes: 1 addition & 1 deletion cmd/cli/kubectl-kyverno/commands/apply/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ func Command() *cobra.Command {
cmd.Flags().StringSliceVarP(&applyCommandConfig.ResourcePaths, "resource", "r", []string{}, "Path to resource files")
cmd.Flags().StringSliceVarP(&applyCommandConfig.ResourcePaths, "resources", "", []string{}, "Path to resource files")
cmd.Flags().BoolVarP(&applyCommandConfig.Cluster, "cluster", "c", false, "Checks if policies should be applied to cluster in the current context")
cmd.Flags().StringVarP(&applyCommandConfig.MutateLogPath, "output", "o", "", "Prints the mutated resources in provided file/directory")
cmd.Flags().StringVarP(&applyCommandConfig.MutateLogPath, "output", "o", "", "Prints the mutated/generated resources in provided file/directory")
// currently `set` flag supports variable for single policy applied on single resource
cmd.Flags().StringVarP(&applyCommandConfig.UserInfoPath, "userinfo", "u", "", "Admission Info including Roles, Cluster Roles and Subjects")
cmd.Flags().StringSliceVarP(&applyCommandConfig.Variables, "set", "s", nil, "Variables that are required")
Expand Down
77 changes: 49 additions & 28 deletions cmd/cli/kubectl-kyverno/processor/policy_processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,9 @@ func (p *PolicyProcessor) ApplyPoliciesOnResource() ([]engineapi.EngineResponse,
} else {
generateResponse.PolicyResponse.Rules = newRuleResponse
}
if err := p.processGenerateResponse(generateResponse, resPath); err != nil {
return responses, err
}
responses = append(responses, generateResponse)
}
p.Rc.addGenerateResponse(generateResponse)
Expand Down Expand Up @@ -342,52 +345,70 @@ func (p *PolicyProcessor) makePolicyContext(
return policyContext, nil
}

func (p *PolicyProcessor) processMutateEngineResponse(response engineapi.EngineResponse, resourcePath string) error {
printMutatedRes := p.Rc.addMutateResponse(response)
if printMutatedRes && p.PrintPatchResource {
yamlEncodedResource, err := yamlv2.Marshal(response.PatchedResource.Object)
func (p *PolicyProcessor) processGenerateResponse(response engineapi.EngineResponse, resourcePath string) error {
generatedResources := []*unstructured.Unstructured{}
for _, rule := range response.PolicyResponse.Rules {
gen := rule.GeneratedResources()
generatedResources = append(generatedResources, gen...)
}
for _, r := range generatedResources {
err := p.printOutput(r.Object, response, resourcePath, true)
if err != nil {
return fmt.Errorf("failed to marshal (%w)", err)
return fmt.Errorf("failed to print generate result (%w)", err)
}
fmt.Fprintf(p.Out, "\n\nGenerate:\nGeneration completed successfully.")
}
return nil
}

if p.MutateLogPath == "" {
mutatedResource := string(yamlEncodedResource) + string("\n---")
if len(strings.TrimSpace(mutatedResource)) > 0 {
if !p.Stdin {
fmt.Fprintf(p.Out, "\nmutate policy %s applied to %s:", response.Policy().GetName(), resourcePath)
}
fmt.Fprintf(p.Out, "\n"+mutatedResource+"\n") //nolint:govet
}
} else {
err := p.printMutatedOutput(string(yamlEncodedResource))
if err != nil {
return fmt.Errorf("failed to print mutated result (%w)", err)
}
fmt.Fprintf(p.Out, "\n\nMutation:\nMutation has been applied successfully. Check the files.")
}
func (p *PolicyProcessor) processMutateEngineResponse(response engineapi.EngineResponse, resourcePath string) error {
p.Rc.addMutateResponse(response)
err := p.printOutput(response.PatchedResource.Object, response, resourcePath, false)
if err != nil {
return fmt.Errorf("failed to print mutated result (%w)", err)
}
fmt.Fprintf(p.Out, "\n\nMutation:\nMutation has been applied successfully.")
return nil
}

func (p *PolicyProcessor) printMutatedOutput(yaml string) error {
func (p *PolicyProcessor) printOutput(resource interface{}, response engineapi.EngineResponse, resourcePath string, isGenerate bool) error {
yamlEncodedResource, err := yamlv2.Marshal(resource)
if err != nil {
return fmt.Errorf("failed to marshal (%w)", err)
}

if p.MutateLogPath == "" {
resource := string(yamlEncodedResource) + string("\n---")
if len(strings.TrimSpace(resource)) > 0 {
if !p.Stdin {
fmt.Fprintf(p.Out, "\npolicy %s applied to %s:", response.Policy().GetName(), resourcePath)
}
fmt.Fprintf(p.Out, "\n"+resource+"\n") //nolint:govet
}
return nil
}

var file *os.File
mutateLogPath := filepath.Clean(p.MutateLogPath)
filename := p.Resource.GetName() + "-mutated"
if isGenerate {
filename = response.Policy().GetName() + "-generated"
}

file, err = os.OpenFile(filepath.Join(mutateLogPath, filename+".yaml"), os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0o600) // #nosec G304
if err != nil {
return err
}

if !p.MutateLogPathIsDir {
// truncation for the case when mutateLogPath is a file (not a directory) is handled under pkg/kyverno/apply/test_command.go
f, err := os.OpenFile(mutateLogPath, os.O_APPEND|os.O_WRONLY, 0o600) // #nosec G304
if err != nil {
return err
}
file = f
} else {
f, err := os.OpenFile(filepath.Join(mutateLogPath, filename+".yaml"), os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0o600) // #nosec G304
if err != nil {
return err
}
file = f
}
if _, err := file.Write([]byte(yaml + "\n---\n\n")); err != nil {
if _, err := file.Write([]byte(string(yamlEncodedResource) + "\n---\n\n")); err != nil {
if err := file.Close(); err != nil {
log.Log.Error(err, "failed to close file")
}
Expand Down
2 changes: 1 addition & 1 deletion docs/user/cli/commands/kyverno_apply.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ kyverno apply [flags]
-h, --help help for apply
--kubeconfig string path to kubeconfig file with authorization and master location information
-n, --namespace string Optional Policy parameter passed with cluster flag
-o, --output string Prints the mutated resources in provided file/directory
-o, --output string Prints the mutated/generated resources in provided file/directory
-p, --policy-report Generates policy report when passed (default policyviolation)
--registry If set to true, access the image registry using local docker credentials to populate external data
--remove-color Remove any color from output
Expand Down

0 comments on commit d100202

Please sign in to comment.