1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package cluster
16
17 import (
18 "context"
19 "fmt"
20
21 "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/randomid"
22 "github.com/cenkalti/backoff"
23 corev1 "k8s.io/api/core/v1"
24 "k8s.io/apimachinery/pkg/api/errors"
25 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
26 "k8s.io/apimachinery/pkg/types"
27 "sigs.k8s.io/controller-runtime/pkg/client"
28 )
29
30
31
32
33
34 func GetNamespaceID(namespaceIDConfigMapNN types.NamespacedName, kubeClient client.Client, ctx context.Context, namespace string) (string, error) {
35 return getOrSetNamespaceId(namespaceIDConfigMapNN, kubeClient, ctx, namespace, nil)
36 }
37
38
39
40
41
42
43 func SetNamespaceID(namespaceIDConfigMapNN types.NamespacedName, kubeClient client.Client, ctx context.Context, namespace, uniqueID string) error {
44 _, err := getOrSetNamespaceId(namespaceIDConfigMapNN, kubeClient, ctx, namespace, &uniqueID)
45 return err
46 }
47
48
49
50 func DeleteNamespaceID(namespaceIDConfigMapNN types.NamespacedName, kubeClient client.Client, ctx context.Context, namespace string) error {
51 var configMap *corev1.ConfigMap
52 var err error
53 deleteNamespaceIDFunc := func() error {
54 configMap, err = createOrGetNamespaceIDConfigMap(namespaceIDConfigMapNN, kubeClient, ctx)
55 if err != nil {
56 return backoff.Permanent(err)
57 }
58 if configMap.Data == nil {
59 return nil
60 }
61 delete(configMap.Data, namespace)
62 err = kubeClient.Update(ctx, configMap)
63 if err == nil || errors.IsConflict(err) {
64 return err
65 }
66 return backoff.Permanent(fmt.Errorf("error deleting namespace id from config map '%v': %w", namespaceIDConfigMapNN, err))
67 }
68 if err := backoff.Retry(deleteNamespaceIDFunc, backoff.NewExponentialBackOff()); err != nil {
69 return err
70 }
71 return nil
72 }
73
74 func getOrSetNamespaceId(namespaceIDConfigMapNN types.NamespacedName, kubeClient client.Client, ctx context.Context, namespace string, idToSet *string) (string, error) {
75 var configMap *corev1.ConfigMap
76 var err error
77 getOrUpdateConfigMapFunc := func() error {
78 configMap, err = createOrGetNamespaceIDConfigMap(namespaceIDConfigMapNN, kubeClient, ctx)
79 if err != nil {
80 return backoff.Permanent(err)
81 }
82 if _, ok := configMap.Data[namespace]; ok && idToSet == nil {
83 return nil
84 }
85 if configMap.Data == nil {
86 configMap.Data = make(map[string]string)
87 }
88 if idToSet == nil {
89 configMap.Data[namespace] = generateID()
90 } else {
91 configMap.Data[namespace] = *idToSet
92 }
93 err = kubeClient.Update(ctx, configMap)
94 if err == nil || errors.IsConflict(err) {
95 return err
96 }
97 return backoff.Permanent(fmt.Errorf("error updating config map '%v': %v", namespaceIDConfigMapNN, err))
98 }
99 if err := backoff.Retry(getOrUpdateConfigMapFunc, backoff.NewExponentialBackOff()); err != nil {
100 return "", err
101 }
102 return configMap.Data[namespace], nil
103 }
104
105 func createOrGetNamespaceIDConfigMap(namespaceIDConfigMapNN types.NamespacedName, kubeClient client.Client, ctx context.Context) (*corev1.ConfigMap, error) {
106 configMap := newConfigMap(namespaceIDConfigMapNN)
107 if err := kubeClient.Create(ctx, &configMap); err == nil {
108 return &configMap, nil
109 } else if !errors.IsAlreadyExists(err) {
110 return nil, fmt.Errorf("error creating configmap '%v': %v", namespaceIDConfigMapNN, err)
111 }
112 if err := kubeClient.Get(ctx, namespaceIDConfigMapNN, &configMap); err != nil {
113 return nil, fmt.Errorf("error getting configmap '%v': %v", namespaceIDConfigMapNN, err)
114 }
115 return &configMap, nil
116 }
117
118 func generateID() string {
119 return randomid.New().String()
120 }
121
122 func newConfigMap(namespaceIDConfigMapNN types.NamespacedName) corev1.ConfigMap {
123 return corev1.ConfigMap{
124 ObjectMeta: metav1.ObjectMeta{
125 Name: namespaceIDConfigMapNN.Name,
126 Namespace: namespaceIDConfigMapNN.Namespace,
127 },
128 }
129 }
130
View as plain text