1515package kyverno
1616
1717import (
18+ "bytes"
19+ "fmt"
20+ "strings"
1821 "time"
22+
23+ "go.yaml.in/yaml/v3"
1924)
2025
2126// KyvernoPolicy represents a Kyverno policy
@@ -34,6 +39,102 @@ type KyvernoPolicy struct {
3439 UpdatedAt * time.Time `json:"updated_at,omitempty"`
3540}
3641
42+ func (k KyvernoPolicy ) GetYamlBytes () ([]byte , error ) {
43+ yamlBytes , err := convertPolicySpecToYAML (k )
44+ if err != nil {
45+ return nil , fmt .Errorf ("failed to convert policy spec to YAML: %w" , err )
46+ }
47+ return []byte (yamlBytes ), nil
48+ }
49+
50+ // Helper function to convert a KyvernoPolicy spec to YAML string
51+ func convertPolicySpecToYAML (policy KyvernoPolicy ) (string , error ) {
52+ // Parse the spec JSON
53+
54+ apiVersion := "kyverno.io/v1"
55+ kind := "ClusterPolicy"
56+ if policy .Kind != "" {
57+ kind = policy .Kind
58+ }
59+ if policy .APIVersion != "" {
60+ apiVersion = policy .APIVersion
61+ }
62+ // Create the full policy structure
63+ policyMap := map [string ]any {
64+ "apiVersion" : apiVersion ,
65+ "kind" : kind ,
66+ "metadata" : map [string ]any {
67+ "name" : policy .Name ,
68+ },
69+ "spec" : policy .Spec ,
70+ }
71+
72+ // Add labels and annotations if they exist and are not empty
73+ if len (policy .Labels ) > 0 {
74+ policyMap ["metadata" ].(map [string ]any )["labels" ] = policy .Labels
75+ }
76+
77+ // Add existing annotations if they exist
78+ if len (policy .Annotations ) > 0 {
79+ policyMap ["metadata" ].(map [string ]any )["annotations" ] = policy .Annotations
80+ }
81+
82+ // Add status only if it exists and is not null
83+ if len (policy .Status ) > 0 {
84+ policyMap ["status" ] = policy .Status
85+ }
86+ // Clean up any null values before marshaling
87+ cleanPolicyMap := cleanNullValues (policyMap )
88+
89+ // Convert to YAML
90+ // yaml converter should use only 2 spaces for indentation
91+ var buf bytes.Buffer
92+ encoder := yaml .NewEncoder (& buf )
93+ encoder .SetIndent (2 )
94+ err := encoder .Encode (cleanPolicyMap )
95+ if err != nil {
96+ return "" , fmt .Errorf ("failed to marshal policy to YAML: %w" , err )
97+ }
98+ yamlContent := buf .String ()
99+ yamlContent = strings .TrimSpace (yamlContent )
100+ return yamlContent , nil
101+ }
102+
103+ // cleanNullValues recursively removes null values from a map
104+ func cleanNullValues (data any ) any {
105+ switch v := data .(type ) {
106+ case map [string ]any :
107+ cleaned := make (map [string ]any )
108+ for key , value := range v {
109+ if value != nil {
110+ cleanedValue := cleanNullValues (value )
111+ if cleanedValue != nil {
112+ cleaned [key ] = cleanedValue
113+ }
114+ }
115+ }
116+ return cleaned
117+ case []any :
118+ var cleaned []any
119+ for _ , item := range v {
120+ if item != nil {
121+ cleanedItem := cleanNullValues (item )
122+ if cleanedItem != nil {
123+ cleaned = append (cleaned , cleanedItem )
124+ }
125+ }
126+ }
127+ return cleaned
128+ case nil :
129+ return nil
130+ case string :
131+ // Don't process strings, return as-is
132+ return v
133+ default :
134+ return v
135+ }
136+ }
137+
37138// GetName implements the nameable interface for download functionality
38139func (k KyvernoPolicy ) GetName () string {
39140 return k .Name
0 commit comments