@@ -17,16 +17,19 @@ limitations under the License.
1717package kustomize
1818
1919import (
20+ "bytes"
2021 "context"
22+ "errors"
2123 "fmt"
24+ "io"
25+ "log"
2226
2327 "gopkg.in/yaml.v3"
24- "k8s.io/apimachinery/pkg/api/errors"
28+ apimachineryerrors "k8s.io/apimachinery/pkg/api/errors"
2529 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
26- "k8s.io/apimachinery/pkg/runtime"
27- "k8s.io/apimachinery/pkg/runtime/serializer"
2830 "sigs.k8s.io/controller-runtime/pkg/client"
2931 "sigs.k8s.io/kustomize/api/krusty"
32+ "sigs.k8s.io/kustomize/api/resmap"
3033 "sigs.k8s.io/kustomize/api/types"
3134 "sigs.k8s.io/kustomize/kyaml/filesys"
3235)
@@ -39,18 +42,10 @@ type ApplyKustomizationOptions struct {
3942// ApplyKustomizationOption is a functional option for ApplyKustomization
4043type ApplyKustomizationOption func (* ApplyKustomizationOptions )
4144
42- // WithIgnoreExistingResources sets the ignore existing option
43- func WithIgnoreExistingResources (ignore bool ) ApplyKustomizationOption {
44- return func (opts * ApplyKustomizationOptions ) {
45- opts .IgnoreExistingResources = ignore
46- }
47- }
48-
4945// ApplyKustomization builds the kustomization and creates the resources
5046func ApplyKustomization (
5147 ctx context.Context ,
5248 cl client.Client ,
53- scheme * runtime.Scheme ,
5449 kustomization * types.Kustomization ,
5550 options ... ApplyKustomizationOption ,
5651) error {
@@ -85,34 +80,60 @@ func ApplyKustomization(
8580 return fmt .Errorf ("failed to run kustomize: %w" , err )
8681 }
8782
88- codecs := serializer . NewCodecFactory ( scheme )
89- deserializer := codecs . UniversalDeserializer ()
83+ return applyResourceMap ( ctx , cl , resourceMap )
84+ }
9085
91- // Apply the resources
92- for _ , res := range resourceMap .Resources () {
93- resJSON , err := res .MarshalJSON ()
94- if err != nil {
95- return fmt .Errorf ("failed to convert resource map to yaml: %w" , err )
86+ func applyResourceMap (ctx context.Context , cl client.Client , resourceMap resmap.ResMap ) error {
87+ yamlBytes , err := resourceMap .AsYaml ()
88+ if err != nil {
89+ return fmt .Errorf ("failed to convert resources to YAML: %w" , err )
90+ }
91+ r := bytes .NewReader (yamlBytes )
92+ dec := yaml .NewDecoder (r )
93+ for {
94+ // parse the YAML doc
95+ obj := & unstructured.Unstructured {Object : map [string ]interface {}{}}
96+ err := dec .Decode (obj .Object )
97+ if errors .Is (err , io .EOF ) {
98+ break
9699 }
97-
98- obj , _ , err := deserializer .Decode (resJSON , nil , nil )
99100 if err != nil {
100- return fmt .Errorf ("failed to decode resource : %w" , err )
101+ return fmt .Errorf ("could not decode object : %w" , err )
101102 }
102- // TODO: review
103- unstructuredObj , err := runtime .DefaultUnstructuredConverter .ToUnstructured (obj )
104- if err != nil {
105- return fmt .Errorf ("failed to convert object to unstructured: %w" , err )
103+ if obj .Object == nil {
104+ continue
106105 }
107- u := & unstructured.Unstructured {Object : unstructuredObj }
106+ if err := applyResource (ctx , cl , obj ); err != nil {
107+ return err
108+ }
109+ }
110+
111+ return nil
112+ }
108113
109- if err := cl .Create (ctx , u ); err != nil {
110- if errors .IsAlreadyExists (err ) && opts .IgnoreExistingResources {
111- continue
114+ func applyResource (ctx context.Context , cl client.Client , obj * unstructured.Unstructured ) error {
115+ if err := cl .Create (ctx , obj ); err != nil {
116+ if apimachineryerrors .IsAlreadyExists (err ) {
117+ // If the resource already exists, retrieve the existing resource
118+ existing := & unstructured.Unstructured {}
119+ existing .SetGroupVersionKind (obj .GroupVersionKind ())
120+ key := client.ObjectKey {
121+ Namespace : obj .GetNamespace (),
122+ Name : obj .GetName (),
112123 }
113- return fmt .Errorf ("failed to apply resource: %w" , err )
124+ if err := cl .Get (ctx , key , existing ); err != nil {
125+ log .Fatalf ("Error getting existing resource: %v" , err )
126+ }
127+
128+ // Update the existing resource with the new data
129+ obj .SetResourceVersion (existing .GetResourceVersion ())
130+ err = cl .Update (ctx , obj )
131+ if err != nil {
132+ return fmt .Errorf ("error updating resource: %v" , err )
133+ }
134+ } else {
135+ return fmt .Errorf ("error creating resource: %v" , err )
114136 }
115137 }
116-
117138 return nil
118139}
0 commit comments