pkg/controllers/configmap_controller.go (100 lines of code) (raw):

// Copyright (c) 2020, 2023, Oracle and/or its affiliates. // // Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ package controllers import ( "context" "encoding/json" "github.com/mysql/ndb-operator/pkg/resources" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/strategicpatch" "k8s.io/apimachinery/pkg/util/wait" "k8s.io/client-go/kubernetes" typedcorev1 "k8s.io/client-go/kubernetes/typed/core/v1" listerscorev1 "k8s.io/client-go/listers/core/v1" "k8s.io/client-go/util/retry" klog "k8s.io/klog/v2" ) type ConfigMapControlInterface interface { EnsureConfigMap(ctx context.Context, sc *SyncContext) (*corev1.ConfigMap, bool, error) PatchConfigMap(ctx context.Context, sc *SyncContext) (*corev1.ConfigMap, error) } type configMapControl struct { k8sClient kubernetes.Interface configMapLister listerscorev1.ConfigMapLister } // NewConfigMapControl creates a new ConfigMapControl func NewConfigMapControl( client kubernetes.Interface, configMapLister listerscorev1.ConfigMapLister) ConfigMapControlInterface { return &configMapControl{ k8sClient: client, configMapLister: configMapLister, } } func (cmc *configMapControl) getConfigMapInterface(namespace string) typedcorev1.ConfigMapInterface { return cmc.k8sClient.CoreV1().ConfigMaps(namespace) } // getConfigMap retrieves the ConfigMap from the API Server func (cmc *configMapControl) getConfigMap(namespace, name string) (*corev1.ConfigMap, error) { // Get configMap from cache return cmc.configMapLister.ConfigMaps(namespace).Get(name) } // EnsureConfigMap creates a config map for the NdbCluster resource if one does not exist already func (cmc *configMapControl) EnsureConfigMap( ctx context.Context, sc *SyncContext) (cm *corev1.ConfigMap, existed bool, err error) { nc := sc.ndb configMapName := nc.GetConfigMapName() cm, err = cmc.getConfigMap(nc.Namespace, configMapName) if err == nil { // ConfigMap already exists if err = sc.isOwnedByNdbCluster(cm); err != nil { // But is not owned by NdbCluster resource return nil, false, err } // ConfigMap exists and is owned by the NdbCluster resource return cm, true, nil } if !errors.IsNotFound(err) { // Failed to lookup ConfigMap klog.Errorf("Failed to retrieve ConfigMap %q : %s", getNamespacedName2(nc.Namespace, configMapName), err) return nil, false, err } // ConfigMap doesn't exist; create it. klog.Infof("Creating ConfigMap %q", getNamespacedName2(nc.Namespace, configMapName)) cm = resources.CreateConfigMap(nc) cm, err = cmc.getConfigMapInterface(nc.Namespace).Create(ctx, cm, metav1.CreateOptions{}) if err != nil { klog.Errorf("Failed to create ConfigMap %q : %s", getNamespacedName2(nc.Namespace, configMapName), err) return nil, false, err } // ConfigMap was created return cm, false, nil } // PatchConfigMap patches the existing config map with new configuration data generated from ndb CRD object func (cmc *configMapControl) PatchConfigMap( ctx context.Context, sc *SyncContext) (cm *corev1.ConfigMap, err error) { nc := sc.ndb configMapName := nc.GetConfigMapName() cmOrg, err := cmc.getConfigMap(nc.Namespace, configMapName) if err != nil { klog.Errorf("Error retrieving ConfigMap %q : %s", getNamespacedName2(nc.Namespace, configMapName), err) return nil, err } // Get an updated config map copy cs := sc.configSummary cmChg := resources.GetUpdatedConfigMap(nc, cmOrg, cs) j, err := json.Marshal(cmOrg) if err != nil { return nil, err } j2, err := json.Marshal(cmChg) if err != nil { return nil, err } patchBytes, err := strategicpatch.CreateTwoWayMergePatch(j, j2, corev1.ConfigMap{}) if err != nil { return nil, err } var result *corev1.ConfigMap ConfigMapInterface := cmc.getConfigMapInterface(nc.Namespace) // Patch the ConfigMap with retries on failure updateErr := wait.ExponentialBackoff(retry.DefaultBackoff, func() (ok bool, err error) { result, err = ConfigMapInterface.Patch( ctx, cmOrg.Name, types.StrategicMergePatchType, patchBytes, metav1.PatchOptions{}) if err != nil { klog.Errorf("Failed to patch ConfigMap %q : %s", getNamespacedName2(nc.Namespace, configMapName), err) return false, err } return true, nil }) klog.Infof("Successfully patched ConfigMap %q", getNamespacedName(cmChg)) return result, updateErr }