目录

更新ConfigMap的工具类

概述

在看 istio的源码, 发现一个更新 ConfigMap 的工具类写的挺不错,分享一下。

代码走读

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
package k8s

import (
	"context"
	"fmt"

	v1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	corev1 "k8s.io/client-go/kubernetes/typed/core/v1"
	listerv1 "k8s.io/client-go/listers/core/v1"

	"istio.io/istio/pkg/config/constants"
)

// InsertDataToConfigMap inserts a data to a configmap in a namespace.
// client: the k8s client interface.
// namespace: the namespace of the configmap.
// value: the value of the data to insert.
// configName: the name of the configmap.
// dataName: the name of the data in the configmap.
func InsertDataToConfigMap(client corev1.ConfigMapsGetter, lister listerv1.ConfigMapLister, meta metav1.ObjectMeta, caBundle []byte) error {
	configmap, err := lister.ConfigMaps(meta.Namespace).Get(meta.Name)
	if err != nil && !errors.IsNotFound(err) {
		return fmt.Errorf("error when getting configmap %v: %v", meta.Name, err)
	}
	if errors.IsNotFound(err) {
		// Create a new ConfigMap.
		configmap = &v1.ConfigMap{
			ObjectMeta: meta,
			Data: map[string]string{
				constants.CACertNamespaceConfigMapDataName: string(caBundle),
			},
		}
		if _, err = client.ConfigMaps(meta.Namespace).Create(context.TODO(), configmap, metav1.CreateOptions{}); err != nil {
			// Namespace may be deleted between now... and our previous check. Just skip this, we cannot create into deleted ns
			// And don't retry a create if the namespace is terminating
			if errors.IsNotFound(err) || errors.HasStatusCause(err, v1.NamespaceTerminatingCause) {
				return nil
			}
			return fmt.Errorf("error when creating configmap %v: %v", meta.Name, err)
		}
	} else {
		// Otherwise, update the config map if changes are required
		err := UpdateDataInConfigMap(client, configmap, caBundle)
		if err != nil {
			return err
		}
	}
	return nil
}

// insertData merges a configmap with a map, and returns true if any changes were made
func insertData(cm *v1.ConfigMap, data map[string]string) bool {
	if cm.Data == nil {
		cm.Data = data
		return true
	}
	needsUpdate := false
	for k, v := range data {
		if cm.Data[k] != v {
			needsUpdate = true
		}
		cm.Data[k] = v
	}
	return needsUpdate
}

func UpdateDataInConfigMap(client corev1.ConfigMapsGetter, cm *v1.ConfigMap, caBundle []byte) error {
	if cm == nil {
		return fmt.Errorf("cannot update nil configmap")
	}
	newCm := cm.DeepCopy()
	data := map[string]string{
		constants.CACertNamespaceConfigMapDataName: string(caBundle),
	}
	if needsUpdate := insertData(newCm, data); !needsUpdate {
		return nil
	}
	if _, err := client.ConfigMaps(newCm.Namespace).Update(context.TODO(), newCm, metav1.UpdateOptions{}); err != nil {
		return fmt.Errorf("error when updating configmap %v: %v", cm.Name, err)
	}
	return nil
}

参考资料

  1. istio的源码
警告
本文最后更新于 2022年4月25日,文中内容可能已过时,请谨慎参考。