func createNewConfigMapFromExisting(akvs *akv.AzureKeyVaultSecret, values map[string]string, existingCM *corev1.ConfigMap) (*corev1.ConfigMap, error) {
	cmName := determineConfigMapName(akvs)
	cmClone := existingCM.DeepCopy()
	ownerRefs := cmClone.GetOwnerReferences()
	if !isOwnedBy(existingCM, akvs) {
		ownerRefs = append(ownerRefs, *newOwnerRef(akvs, schema.GroupVersionKind{
			Group:   akv.SchemeGroupVersion.Group,
			Version: akv.SchemeGroupVersion.Version,
			Kind:    "AzureKeyVaultSecret",
		}))
	}
	mergedValues := mergeValuesWithExistingConfigMap(values, existingCM)
	return &corev1.ConfigMap{
		ObjectMeta: metav1.ObjectMeta{
			Name:            cmName,
			Namespace:       akvs.Namespace,
			Labels:          akvs.Labels,
			Annotations:     akvs.Annotations,
			OwnerReferences: ownerRefs,
		},
		Data: mergedValues,
	}, nil
}
updateExistingSecret creates a new Secret for a AzureKeyVaultSecret resource. It also sets
the appropriate OwnerReferences on the resource so handleObject can discover
the AzureKeyVaultSecret resource that 'owns' it.
package controller
import (
	"bytes"
	"context"
	"crypto/md5"
	"encoding/hex"
	"fmt"
	"sort"
	akv "github.com/SparebankenVest/azure-key-vault-to-kubernetes/pkg/k8s/apis/azurekeyvault/v2beta1"
	"k8s.io/klog/v2"
	corev1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/client-go/tools/cache"
)
func convertToConfigMap(obj interface{}) (*corev1.ConfigMap, error) {
	cm, ok := obj.(*corev1.ConfigMap)
	if !ok {
		tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
		if !ok {
			return nil, fmt.Errorf("couldn't get object from tombstone %#v", obj)
		}
		cm, ok = tombstone.Obj.(*corev1.ConfigMap)
		if !ok {
			return nil, fmt.Errorf("tombstone contained object that is not a ConfigMap %#v", obj)
		}
	}
	return cm, nil
}
func (c *Controller) getConfigMapByKey(key string) (*corev1.ConfigMap, error) {
	namespace, name, err := cache.SplitMetaNamespaceKey(key)
	if err != nil {
		return nil, fmt.Errorf("invalid resource key: %s", key)
	}
	return c.getConfigMap(namespace, name)
}
func (c *Controller) getConfigMap(ns, name string) (*corev1.ConfigMap, error) {
	klog.V(4).InfoS("getting configmap", "configmap", klog.KRef(ns, name))
	cm, err := c.configMapsLister.ConfigMaps(ns).Get(name)
	if err != nil {
		return nil, err
	}
	return cm, err
}
func (c *Controller) deleteKubernetesConfigMapValues(akvs *akv.AzureKeyVaultSecret) error {
	cm, err := c.getConfigMap(akvs.Namespace, akvs.Spec.Output.ConfigMap.Name)
	if errors.IsNotFound(err) {
		return nil
	}
	cmData := cm.Data
	data, err := c.getConfigMapFromKeyVault(akvs)
	if err != nil {
		return err
	}
	for key := range data {
		delete(cmData, key)
	}
	newCM, err := createNewConfigMapFromExistingWithUpdatedValues(akvs, cmData, cm)
	if err != nil {
		return err
	}
	cm, err = c.kubeclientset.CoreV1().ConfigMaps(akvs.Namespace).Update(context.TODO(), newCM, metav1.UpdateOptions{})
	if err != nil {
		return err
	}
	return nil
}
func (c *Controller) getOrCreateKubernetesConfigMap(akvs *akv.AzureKeyVaultSecret) (*corev1.ConfigMap, error) {
	var cm *corev1.ConfigMap
	var cmValues map[string]string
	var err error
	cmName := akvs.Spec.Output.ConfigMap.Name
	if cmName == "" {
		return nil, fmt.Errorf("output configmap name must be specified using spec.output.configMap.name")
	}
	klog.V(4).InfoS("get or create configmap", "configmap", klog.KRef(akvs.Namespace, cmName))
	if cm, err = c.configMapsLister.ConfigMaps(akvs.Namespace).Get(cmName); err != nil {
		klog.V(4).ErrorS(err, "failed to get configmap ", "configmap", klog.KRef(akvs.Namespace, cmName))
		if errors.IsNotFound(err) {
			klog.V(4).InfoS("configmap was not found", "configmap", klog.KRef(akvs.Namespace, cmName))
			klog.V(4).InfoS("getting configmap value from azure key vault", "configmap", klog.KRef(akvs.Namespace, cmName))
			cmValues, err = c.getConfigMapFromKeyVault(akvs)
			if err != nil {
				return nil, fmt.Errorf("failed to get configmap from azure key vault for configmap '%s'/'%s', error: %+v", akvs.Namespace, akvs.Name, err)
			}
			if cm, err = c.kubeclientset.CoreV1().ConfigMaps(akvs.Namespace).Create(context.TODO(), createNewConfigMap(akvs, cmValues), metav1.CreateOptions{}); err != nil {
				return nil, fmt.Errorf("failed to create new configmap, err: %+v", err)
			}
			klog.InfoS("updating status for azurekeyvaultsecret", "azurekeyvaultsecret", klog.KObj(akvs))
			if err = c.updateAzureKeyVaultSecretStatusForConfigMap(akvs, getMD5HashOfStringValues(cmValues)); err != nil {
				return nil, fmt.Errorf("failed to update status for azurekeyvaultsecret %s, error: %+v", akvs.Name, err)
			}
			return cm, nil
		}
	}
	klog.V(4).InfoS("getting secret from azure key vault", "azurekeyvaultsecret", klog.KObj(akvs))
	cmValues, err = c.getConfigMapFromKeyVault(akvs)
	if err != nil {
		return nil, fmt.Errorf("failed to get secret from Azure Key Vault for secret '%s'/'%s', error: %+v", akvs.Namespace, akvs.Name, err)
	}
	if cmName != cm.Name {
		if !hasMultipleOwners(cm.GetOwnerReferences()) {
			if err = c.kubeclientset.CoreV1().ConfigMaps(akvs.Namespace).Delete(context.TODO(), cm.Name, metav1.DeleteOptions{}); err != nil {
				return nil, err
			}
		}
		if cm, err = c.kubeclientset.CoreV1().ConfigMaps(akvs.Namespace).Create(context.TODO(), createNewConfigMap(akvs, cmValues), metav1.CreateOptions{}); err != nil {
			return nil, err
		}
		return cm, nil
	}
	if hasAzureKeyVaultSecretChangedForConfigMap(akvs, cmValues, cm) {
		klog.InfoS("values have changed requiring update to configmap", "azurekeyvaultsecret", klog.KObj(akvs), "configmap", klog.KObj(cm))
		updatedCM, err := createNewConfigMapFromExisting(akvs, cmValues, cm)
		if err != nil {
			return nil, err
		}
		cm, err = c.kubeclientset.CoreV1().ConfigMaps(akvs.Namespace).Update(context.TODO(), updatedCM, metav1.UpdateOptions{})
		if err == nil {
			klog.InfoS("configmap updated", "azurekeyvaultsecret", klog.KObj(akvs), "configmap", klog.KObj(cm))
		}
	}
	return cm, err
}
func createNewConfigMap(azureKeyVaultSecret *akv.AzureKeyVaultSecret, azureSecretValue map[string]string) *corev1.ConfigMap {
	cmName := determineConfigMapName(azureKeyVaultSecret)
	return &corev1.ConfigMap{
		ObjectMeta: metav1.ObjectMeta{
			Name:        cmName,
			Namespace:   azureKeyVaultSecret.Namespace,
			Labels:      azureKeyVaultSecret.Labels,
			Annotations: azureKeyVaultSecret.Annotations,
			OwnerReferences: []metav1.OwnerReference{
				*newOwnerRef(azureKeyVaultSecret, schema.GroupVersionKind{
					Group:   akv.SchemeGroupVersion.Group,
					Version: akv.SchemeGroupVersion.Version,
					Kind:    "AzureKeyVaultSecret",
				}),
			},
		},
		Data: azureSecretValue,
	}
}
func newOwnerRef(owner metav1.Object, gvk schema.GroupVersionKind) *metav1.OwnerReference {
	blockOwnerDeletion := true
	isController := false
	return &metav1.OwnerReference{
		APIVersion:         gvk.GroupVersion().String(),
		Kind:               gvk.Kind,
		Name:               owner.GetName(),
		UID:                owner.GetUID(),
		BlockOwnerDeletion: &blockOwnerDeletion,
		Controller:         &isController,
	}
}