11package fluxsync
22
33import (
4- "errors"
5-
64 helmv2 "github.com/fluxcd/helm-controller/api/v2beta1"
75 imgautomationv1 "github.com/fluxcd/image-automation-controller/api/v1beta1"
86 reflectorv1 "github.com/fluxcd/image-reflector-controller/api/v1beta2"
97 kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1"
108 "github.com/fluxcd/pkg/apis/meta"
119 sourcev1 "github.com/fluxcd/source-controller/api/v1"
1210 sourcev1b2 "github.com/fluxcd/source-controller/api/v1beta2"
11+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
12+ "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
13+ "k8s.io/apimachinery/pkg/runtime"
1314 "k8s.io/apimachinery/pkg/runtime/schema"
1415 "sigs.k8s.io/controller-runtime/pkg/client"
1516)
@@ -23,7 +24,7 @@ type Reconcilable interface {
2324 GetLastHandledReconcileRequest () string
2425 AsClientObject () client.Object
2526 GroupVersionKind () schema.GroupVersionKind
26- SetSuspended (suspend bool )
27+ SetSuspended (suspend bool ) error
2728 DeepCopyClientObject () client.Object
2829}
2930
@@ -42,30 +43,6 @@ type Automation interface {
4243 SourceRef () SourceRef
4344}
4445
45- func NewReconcileable (obj client.Object ) Reconcilable {
46- switch o := obj .(type ) {
47- case * kustomizev1.Kustomization :
48- return KustomizationAdapter {Kustomization : o }
49- case * helmv2.HelmRelease :
50- return HelmReleaseAdapter {HelmRelease : o }
51- case * sourcev1.GitRepository :
52- return GitRepositoryAdapter {GitRepository : o }
53- case * sourcev1b2.HelmRepository :
54- return HelmRepositoryAdapter {HelmRepository : o }
55- case * sourcev1b2.Bucket :
56- return BucketAdapter {Bucket : o }
57- case * sourcev1b2.HelmChart :
58- return HelmChartAdapter {HelmChart : o }
59- case * sourcev1b2.OCIRepository :
60- return OCIRepositoryAdapter {OCIRepository : o }
61- case * reflectorv1.ImageRepository :
62- return ImageRepositoryAdapter {ImageRepository : o }
63- case * imgautomationv1.ImageUpdateAutomation :
64- return ImageUpdateAutomationAdapter {ImageUpdateAutomation : o }
65- }
66- return nil
67- }
68-
6946type GitRepositoryAdapter struct {
7047 * sourcev1.GitRepository
7148}
@@ -82,8 +59,9 @@ func (obj GitRepositoryAdapter) GroupVersionKind() schema.GroupVersionKind {
8259 return sourcev1 .GroupVersion .WithKind (sourcev1 .GitRepositoryKind )
8360}
8461
85- func (obj GitRepositoryAdapter ) SetSuspended (suspend bool ) {
62+ func (obj GitRepositoryAdapter ) SetSuspended (suspend bool ) error {
8663 obj .Spec .Suspend = suspend
64+ return nil
8765}
8866
8967func (obj GitRepositoryAdapter ) DeepCopyClientObject () client.Object {
@@ -106,8 +84,9 @@ func (obj BucketAdapter) GroupVersionKind() schema.GroupVersionKind {
10684 return sourcev1b2 .GroupVersion .WithKind (sourcev1b2 .BucketKind )
10785}
10886
109- func (obj BucketAdapter ) SetSuspended (suspend bool ) {
87+ func (obj BucketAdapter ) SetSuspended (suspend bool ) error {
11088 obj .Spec .Suspend = suspend
89+ return nil
11190}
11291
11392func (obj BucketAdapter ) DeepCopyClientObject () client.Object {
@@ -130,8 +109,9 @@ func (obj HelmChartAdapter) GroupVersionKind() schema.GroupVersionKind {
130109 return sourcev1b2 .GroupVersion .WithKind (sourcev1b2 .HelmChartKind )
131110}
132111
133- func (obj HelmChartAdapter ) SetSuspended (suspend bool ) {
112+ func (obj HelmChartAdapter ) SetSuspended (suspend bool ) error {
134113 obj .Spec .Suspend = suspend
114+ return nil
135115}
136116
137117func (obj HelmChartAdapter ) DeepCopyClientObject () client.Object {
@@ -154,8 +134,9 @@ func (obj HelmRepositoryAdapter) GroupVersionKind() schema.GroupVersionKind {
154134 return sourcev1b2 .GroupVersion .WithKind (sourcev1b2 .HelmRepositoryKind )
155135}
156136
157- func (obj HelmRepositoryAdapter ) SetSuspended (suspend bool ) {
137+ func (obj HelmRepositoryAdapter ) SetSuspended (suspend bool ) error {
158138 obj .Spec .Suspend = suspend
139+ return nil
159140}
160141
161142func (obj HelmRepositoryAdapter ) DeepCopyClientObject () client.Object {
@@ -178,8 +159,9 @@ func (obj OCIRepositoryAdapter) GroupVersionKind() schema.GroupVersionKind {
178159 return sourcev1b2 .GroupVersion .WithKind (sourcev1b2 .OCIRepositoryKind )
179160}
180161
181- func (obj OCIRepositoryAdapter ) SetSuspended (suspend bool ) {
162+ func (obj OCIRepositoryAdapter ) SetSuspended (suspend bool ) error {
182163 obj .Spec .Suspend = suspend
164+ return nil
183165}
184166
185167func (obj OCIRepositoryAdapter ) DeepCopyClientObject () client.Object {
@@ -213,8 +195,9 @@ func (obj HelmReleaseAdapter) GroupVersionKind() schema.GroupVersionKind {
213195 return helmv2 .GroupVersion .WithKind (helmv2 .HelmReleaseKind )
214196}
215197
216- func (obj HelmReleaseAdapter ) SetSuspended (suspend bool ) {
198+ func (obj HelmReleaseAdapter ) SetSuspended (suspend bool ) error {
217199 obj .Spec .Suspend = suspend
200+ return nil
218201}
219202
220203func (obj HelmReleaseAdapter ) DeepCopyClientObject () client.Object {
@@ -246,8 +229,9 @@ func (obj KustomizationAdapter) GroupVersionKind() schema.GroupVersionKind {
246229 return kustomizev1 .GroupVersion .WithKind (kustomizev1 .KustomizationKind )
247230}
248231
249- func (obj KustomizationAdapter ) SetSuspended (suspend bool ) {
232+ func (obj KustomizationAdapter ) SetSuspended (suspend bool ) error {
250233 obj .Spec .Suspend = suspend
234+ return nil
251235}
252236
253237func (obj KustomizationAdapter ) DeepCopyClientObject () client.Object {
@@ -270,8 +254,9 @@ func (obj ImageRepositoryAdapter) GroupVersionKind() schema.GroupVersionKind {
270254 return reflectorv1 .GroupVersion .WithKind (reflectorv1 .ImageRepositoryKind )
271255}
272256
273- func (obj ImageRepositoryAdapter ) SetSuspended (suspend bool ) {
257+ func (obj ImageRepositoryAdapter ) SetSuspended (suspend bool ) error {
274258 obj .Spec .Suspend = suspend
259+ return nil
275260}
276261
277262func (obj ImageRepositoryAdapter ) DeepCopyClientObject () client.Object {
@@ -294,14 +279,61 @@ func (obj ImageUpdateAutomationAdapter) GroupVersionKind() schema.GroupVersionKi
294279 return imgautomationv1 .GroupVersion .WithKind (imgautomationv1 .ImageUpdateAutomationKind )
295280}
296281
297- func (obj ImageUpdateAutomationAdapter ) SetSuspended (suspend bool ) {
282+ func (obj ImageUpdateAutomationAdapter ) SetSuspended (suspend bool ) error {
298283 obj .Spec .Suspend = suspend
284+ return nil
299285}
300286
301287func (obj ImageUpdateAutomationAdapter ) DeepCopyClientObject () client.Object {
302288 return obj .DeepCopy ()
303289}
304290
291+ // UnstructuredAdapter implements the Reconcilable interface for unstructured resources.
292+ // The underlying resource gvk should have the standard flux object sync/suspend fields
293+ type UnstructuredAdapter struct {
294+ * unstructured.Unstructured
295+ }
296+
297+ func (obj UnstructuredAdapter ) GetLastHandledReconcileRequest () string {
298+ if val , found , _ := unstructured .NestedString (obj .Object , "status" , "lastHandledReconcileAt" ); found {
299+ return val
300+ }
301+ return ""
302+ }
303+
304+ func (obj UnstructuredAdapter ) GetConditions () []metav1.Condition {
305+ conditionsSlice , found , err := unstructured .NestedSlice (obj .Object , "status" , "conditions" )
306+ if ! found || err != nil {
307+ return nil
308+ }
309+
310+ var conditions []metav1.Condition
311+ for _ , c := range conditionsSlice {
312+ var condition metav1.Condition
313+ if err := runtime .DefaultUnstructuredConverter .FromUnstructured (c .(map [string ]interface {}), & condition ); err != nil {
314+ continue
315+ }
316+ conditions = append (conditions , condition )
317+ }
318+
319+ return conditions
320+ }
321+
322+ func (obj UnstructuredAdapter ) AsClientObject () client.Object {
323+ // Important for the controller-runtime type reflection to work
324+ // We can't return just `obj` here otherwise we get a
325+ // panic: reflect: call of reflect.Value.Elem on struct Value
326+ return obj .Unstructured
327+ }
328+
329+ func (obj UnstructuredAdapter ) SetSuspended (suspend bool ) error {
330+ return unstructured .SetNestedField (obj .Object , suspend , "spec" , "suspend" )
331+ }
332+
333+ func (obj UnstructuredAdapter ) DeepCopyClientObject () client.Object {
334+ return obj .DeepCopy ()
335+ }
336+
305337type sRef struct {
306338 apiVersion string
307339 name string
@@ -325,35 +357,39 @@ func (s sRef) Kind() string {
325357 return s .kind
326358}
327359
328- func ToReconcileable (kind string ) (client.ObjectList , Reconcilable , error ) {
329- switch kind {
360+ // ToReconcileable takes a GVK and returns a "Reconcilable" for it.
361+ // The reconcilable can be passed to a controller-runtime client to fetch it
362+ // from the cluster. Once fetched we can query it for the last sync time, whether
363+ // its suspended etc, using the Reconcilable interface.
364+ //
365+ // The generic unstructured case handles "flux like" objects that we don't explicitly
366+ // know about, but which follow the same patterns for suspend/sync as a stadard flux object.
367+ // E.g. `spec.suspend` and `status.lastHandledReconcileRequest` etc.
368+ func ToReconcileable (gvk schema.GroupVersionKind ) Reconcilable {
369+ switch gvk .Kind {
330370 case kustomizev1 .KustomizationKind :
331- return & kustomizev1.KustomizationList {}, NewReconcileable (& kustomizev1.Kustomization {}), nil
332-
371+ return KustomizationAdapter {Kustomization : & kustomizev1.Kustomization {}}
333372 case helmv2 .HelmReleaseKind :
334- return & helmv2. HelmReleaseList {}, NewReconcileable ( & helmv2.HelmRelease {}), nil
335-
373+ return HelmReleaseAdapter { HelmRelease : & helmv2.HelmRelease {}}
374+ // TODO: remove all these and let them fall through to the Unstructured case?
336375 case sourcev1 .GitRepositoryKind :
337- return & sourcev1.GitRepositoryList {}, NewReconcileable (& sourcev1.GitRepository {}), nil
338-
376+ return GitRepositoryAdapter {GitRepository : & sourcev1.GitRepository {}}
339377 case sourcev1b2 .BucketKind :
340- return & sourcev1b2.BucketList {}, NewReconcileable (& sourcev1b2.Bucket {}), nil
341-
378+ return BucketAdapter {Bucket : & sourcev1b2.Bucket {}}
342379 case sourcev1b2 .HelmRepositoryKind :
343- return & sourcev1b2.HelmRepositoryList {}, NewReconcileable (& sourcev1b2.HelmRepository {}), nil
344-
380+ return HelmRepositoryAdapter {HelmRepository : & sourcev1b2.HelmRepository {}}
345381 case sourcev1b2 .HelmChartKind :
346- return & sourcev1b2.HelmChartList {}, NewReconcileable (& sourcev1b2.HelmChart {}), nil
347-
382+ return HelmChartAdapter {HelmChart : & sourcev1b2.HelmChart {}}
348383 case sourcev1b2 .OCIRepositoryKind :
349- return & sourcev1b2.OCIRepositoryList {}, NewReconcileable (& sourcev1b2.OCIRepository {}), nil
350-
384+ return OCIRepositoryAdapter {OCIRepository : & sourcev1b2.OCIRepository {}}
351385 case reflectorv1 .ImageRepositoryKind :
352- return & reflectorv1.ImageRepositoryList {}, NewReconcileable (& reflectorv1.ImageRepository {}), nil
353-
386+ return ImageRepositoryAdapter {ImageRepository : & reflectorv1.ImageRepository {}}
354387 case imgautomationv1 .ImageUpdateAutomationKind :
355- return & imgautomationv1. ImageUpdateAutomationList {}, NewReconcileable ( & imgautomationv1.ImageUpdateAutomation {}), nil
388+ return ImageUpdateAutomationAdapter { ImageUpdateAutomation : & imgautomationv1.ImageUpdateAutomation {}}
356389 }
357390
358- return nil , nil , errors .New ("could not find source type" )
391+ // Return the UnstructuredAdapter for flux-like resources
392+ obj := & unstructured.Unstructured {}
393+ obj .SetGroupVersionKind (gvk )
394+ return UnstructuredAdapter {Unstructured : obj }
359395}
0 commit comments