@@ -50,6 +50,7 @@ import (
50
50
apiextensionsclient "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
51
51
apierrors "k8s.io/apimachinery/pkg/api/errors"
52
52
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
53
+ "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
53
54
"k8s.io/apimachinery/pkg/fields"
54
55
"k8s.io/apimachinery/pkg/runtime"
55
56
"k8s.io/apimachinery/pkg/runtime/schema"
@@ -58,6 +59,7 @@ import (
58
59
"k8s.io/apimachinery/pkg/util/intstr"
59
60
"k8s.io/apimachinery/pkg/util/wait"
60
61
"k8s.io/apimachinery/pkg/watch"
62
+ "k8s.io/client-go/dynamic"
61
63
"k8s.io/client-go/kubernetes"
62
64
"k8s.io/client-go/metadata"
63
65
"k8s.io/client-go/rest"
@@ -81,6 +83,7 @@ type Client struct {
81
83
userWorkloadNamespace string
82
84
83
85
kclient kubernetes.Interface
86
+ dclient dynamic.Interface
84
87
mdataclient metadata.Interface
85
88
osmclient openshiftmonitoringclientset.Interface
86
89
oscclient openshiftconfigclientset.Interface
@@ -107,6 +110,14 @@ func NewForConfig(cfg *rest.Config, version string, namespace, userWorkloadNames
107
110
client .kclient = kclient
108
111
}
109
112
113
+ if client .dclient == nil {
114
+ dclient , err := dynamic .NewForConfig (cfg )
115
+ if err != nil {
116
+ return nil , fmt .Errorf ("creating dynamic clientset client: %w" , err )
117
+ }
118
+ client .dclient = dclient
119
+ }
120
+
110
121
if client .eclient == nil {
111
122
eclient , err := apiextensionsclient .NewForConfig (cfg )
112
123
if err != nil {
@@ -203,6 +214,12 @@ func KubernetesClient(kclient kubernetes.Interface) Option {
203
214
}
204
215
}
205
216
217
+ func DynamicClient (dclient * dynamic.DynamicClient ) Option {
218
+ return func (c * Client ) {
219
+ c .dclient = dclient
220
+ }
221
+ }
222
+
206
223
func OpenshiftMonitoringClient (osmclient openshiftmonitoringclientset.Interface ) Option {
207
224
return func (c * Client ) {
208
225
c .osmclient = osmclient
@@ -632,29 +649,75 @@ func (c *Client) GetAlertingRule(ctx context.Context, namespace, name string) (*
632
649
return c .osmclient .MonitoringV1 ().AlertingRules (namespace ).Get (ctx , name , metav1.GetOptions {})
633
650
}
634
651
635
- func (c * Client ) CreateOrUpdatePrometheus (ctx context.Context , p * monv1.Prometheus ) error {
636
- pclient := c .mclient .MonitoringV1 ().Prometheuses (p .GetNamespace ())
637
- existing , err := pclient .Get (ctx , p .GetName (), metav1.GetOptions {})
652
+ // CreateOrUpdatePrometheus does not use a defaulting function, and resorts only to the caching mechanism, since,
653
+ // * defaults for Prometheus should be introduced from its operator level, and,
654
+ // * the defaulting approach generally requires hardcoding the default values, which adds on to the maintenance overhead.
655
+ // NOTE: The return values establish the following matrix (w.r.t. the create or update verbs):
656
+ // * true, nil : verb action needed; operation successful,
657
+ // * false, nil : verb action not needed; operation skipped,
658
+ // * true, error : verb action needed, operation unsuccessful.
659
+ // * false, error: verb action may or may not be needed; operation unsuccessful,
660
+ func (c * Client ) CreateOrUpdatePrometheus (ctx context.Context , structuredRequiredPrometheus * monv1.Prometheus ) (bool , error ) {
661
+ unstructuredRequiredPrometheusObject , err := runtime .DefaultUnstructuredConverter .ToUnstructured (structuredRequiredPrometheus )
662
+ if err != nil {
663
+ return false , fmt .Errorf ("converting Prometheus object to unstructured failed: %w" , err )
664
+ }
665
+ unstructuredRequiredPrometheus := & unstructured.Unstructured {}
666
+ unstructuredRequiredPrometheus .SetUnstructuredContent (unstructuredRequiredPrometheusObject )
667
+
668
+ // Set the GVK for the unstructured object, since these are not inferred automatically, unlike their structured counterparts.
669
+ unstructuredRequiredPrometheus .SetGroupVersionKind (monv1 .SchemeGroupVersion .WithKind (monv1 .PrometheusesKind ))
670
+
671
+ // Preserve the original behavior: always merge the metadata, never replace.
672
+ // Refer: https://github.com/openshift/cluster-monitoring-operator/pull/942.
673
+ prometheusGVR := unstructuredRequiredPrometheus .GroupVersionKind ().GroupVersion ().WithResource (monv1 .PrometheusName )
674
+ unstructuredExistingPrometheus , err := c .dclient .
675
+ Resource (prometheusGVR ).
676
+ Namespace (structuredRequiredPrometheus .GetNamespace ()).
677
+ Get (ctx , structuredRequiredPrometheus .GetName (), metav1.GetOptions {})
638
678
if apierrors .IsNotFound (err ) {
639
- _ , err := pclient .Create (ctx , p , metav1.CreateOptions {})
679
+ _ , didUpdate , err := resourceapply .ApplyUnstructuredResourceImproved (
680
+ ctx ,
681
+ c .dclient ,
682
+ c .eventRecorder ,
683
+ unstructuredRequiredPrometheus ,
684
+ c .resourceCache ,
685
+ prometheusGVR ,
686
+ nil ,
687
+ nil ,
688
+ )
640
689
if err != nil {
641
- return fmt .Errorf ("creating Prometheus object failed: %w" , err )
690
+ return didUpdate , fmt .Errorf ("creating Prometheus object failed: %w" , err )
642
691
}
643
- return nil
692
+
693
+ return true , nil
644
694
}
645
695
if err != nil {
646
- return fmt .Errorf ("retrieving Prometheus object failed: %w" , err )
696
+ return false , fmt .Errorf ("retrieving Prometheus object failed: %w" , err )
647
697
}
698
+ unstructuredRequiredPrometheusMetadataLabels := unstructuredRequiredPrometheus .GetLabels ()
699
+ unstructuredRequiredPrometheusMetadataAnnotations := unstructuredRequiredPrometheus .GetAnnotations ()
700
+ mergeMetadataLabels (unstructuredRequiredPrometheusMetadataLabels , unstructuredExistingPrometheus .GetLabels ())
701
+ mergeMetadataAnnotations (unstructuredRequiredPrometheusMetadataAnnotations , unstructuredExistingPrometheus .GetAnnotations ())
702
+ unstructuredRequiredPrometheus .SetLabels (unstructuredRequiredPrometheusMetadataLabels )
703
+ unstructuredRequiredPrometheus .SetAnnotations (unstructuredRequiredPrometheusMetadataAnnotations )
704
+ unstructuredRequiredPrometheus .SetResourceVersion (unstructuredExistingPrometheus .GetResourceVersion ())
648
705
649
- required := p .DeepCopy ()
650
- mergeMetadata (& required .ObjectMeta , existing .ObjectMeta )
651
-
652
- required .ResourceVersion = existing .ResourceVersion
653
- _ , err = pclient .Update (ctx , required , metav1.UpdateOptions {})
706
+ _ , didUpdate , err := resourceapply .ApplyUnstructuredResourceImproved (
707
+ ctx ,
708
+ c .dclient ,
709
+ c .eventRecorder ,
710
+ unstructuredRequiredPrometheus ,
711
+ c .resourceCache ,
712
+ prometheusGVR ,
713
+ nil ,
714
+ nil ,
715
+ )
654
716
if err != nil {
655
- return fmt .Errorf ("updating Prometheus object failed: %w" , err )
717
+ return didUpdate , fmt .Errorf ("updating Prometheus object failed: %w" , err )
656
718
}
657
- return nil
719
+
720
+ return didUpdate , nil
658
721
}
659
722
660
723
func (c * Client ) CreateOrUpdatePrometheusRule (ctx context.Context , p * monv1.PrometheusRule ) error {
@@ -1878,20 +1941,28 @@ func (c *Client) VPACustomResourceDefinitionPresent(ctx context.Context, lastKno
1878
1941
// where keys starting from string defined in `metadataPrefix` are deleted. This prevents issues with preserving stale
1879
1942
// metadata defined by the operator
1880
1943
func mergeMetadata (required * metav1.ObjectMeta , existing metav1.ObjectMeta ) {
1881
- for k := range existing .Annotations {
1944
+ mergeMetadataLabels (required .Labels , existing .Labels )
1945
+ mergeMetadataAnnotations (required .Annotations , existing .Annotations )
1946
+ }
1947
+
1948
+ func mergeMetadataLabels (requiredLabels map [string ]string , existingLabels map [string ]string ) {
1949
+ for k := range existingLabels {
1882
1950
if strings .HasPrefix (k , metadataPrefix ) {
1883
- delete (existing . Annotations , k )
1951
+ delete (existingLabels , k )
1884
1952
}
1885
1953
}
1886
1954
1887
- for k := range existing .Labels {
1955
+ _ = mergo .Merge (& requiredLabels , existingLabels )
1956
+ }
1957
+
1958
+ func mergeMetadataAnnotations (requiredAnnotations map [string ]string , existingAnnotations map [string ]string ) {
1959
+ for k := range existingAnnotations {
1888
1960
if strings .HasPrefix (k , metadataPrefix ) {
1889
- delete (existing . Labels , k )
1961
+ delete (existingAnnotations , k )
1890
1962
}
1891
1963
}
1892
1964
1893
- _ = mergo .Merge (& required .Annotations , existing .Annotations )
1894
- _ = mergo .Merge (& required .Labels , existing .Labels )
1965
+ _ = mergo .Merge (& requiredAnnotations , existingAnnotations )
1895
1966
}
1896
1967
1897
1968
type jsonPatch struct {
0 commit comments