Skip to content

Commit eb249d6

Browse files
Huanle Hancaicloud-bot
authored andcommitted
feat: support custom configs for lb (#131)
1 parent 43bd814 commit eb249d6

File tree

1 file changed

+141
-41
lines changed

1 file changed

+141
-41
lines changed

pkg/proxy/nginx/config.go

Lines changed: 141 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ limitations under the License.
1717
package nginx
1818

1919
import (
20+
"encoding/json"
2021
"fmt"
2122
"reflect"
2223

@@ -47,89 +48,188 @@ var (
4748
"limit-conn-zone-variable": "",
4849
"whitelist-source-range": "",
4950
}
51+
52+
annotationExternalConfigMaps string = "external-configs"
5053
)
5154

52-
func merge(base, del, add map[string]string) map[string]string {
55+
func mapDel(base map[string]string, dels ...map[string]string) map[string]string {
5356
ret := make(map[string]string)
54-
5557
for k, v := range base {
56-
if del != nil {
57-
if _, has := del[k]; has {
58-
continue
58+
has := false
59+
for _, del := range dels {
60+
if _, has = del[k]; has {
61+
break
5962
}
6063
}
61-
ret[k] = v
64+
if !has {
65+
ret[k] = v
66+
}
6267
}
6368

64-
for k, v := range add {
69+
return ret
70+
}
71+
func mapAdd(base map[string]string, adds ...map[string]string) map[string]string {
72+
ret := make(map[string]string)
73+
for k, v := range base {
6574
ret[k] = v
6675
}
6776

77+
for _, add := range adds {
78+
for k, v := range add {
79+
ret[k] = v
80+
}
81+
}
82+
6883
return ret
6984
}
7085

7186
func (f *nginx) ensureConfigMaps(lb *lbapi.LoadBalancer) error {
7287
labels := f.selector(lb)
7388

89+
// For ingress-nginx configuration
7490
cmName := fmt.Sprintf(configMapName, lb.Name)
75-
config := merge(defaultConfig, nil, lb.Spec.Proxy.Config)
76-
err := f.ensureConfigMap(cmName, lb.Namespace, labels, managedConfig, config)
91+
cm, err := f.ensureConfigMap(cmName, lb.Namespace, labels)
92+
if err != nil {
93+
return err
94+
}
95+
96+
err = f.updateConfig(lb, cm)
7797
if err != nil {
7898
return err
7999
}
100+
101+
// For L4 TCP rules
80102
tcpcmName := fmt.Sprintf(tcpConfigMapName, lb.Name)
81-
err = f.ensureConfigMap(tcpcmName, lb.Namespace, labels, nil, nil)
103+
_, err = f.ensureConfigMap(tcpcmName, lb.Namespace, labels)
82104
if err != nil {
83105
return err
84106
}
107+
108+
// For L4 UDP rules
85109
udpcmName := fmt.Sprintf(udpConfigMapName, lb.Name)
86-
err = f.ensureConfigMap(udpcmName, lb.Namespace, labels, nil, nil)
110+
_, err = f.ensureConfigMap(udpcmName, lb.Namespace, labels)
87111

88112
return err
89113
}
90114

91-
func (f *nginx) ensureConfigMap(name, namespace string, labels, del, data map[string]string) error {
115+
func (f *nginx) ensureConfigMap(name, namespace string, labels map[string]string) (*v1.ConfigMap, error) {
92116
cm, err := f.client.CoreV1().ConfigMaps(namespace).Get(name, metav1.GetOptions{})
93117

94-
if err != nil && !errors.IsNotFound(err) {
118+
if err == nil {
119+
return cm, nil
120+
}
121+
122+
if !errors.IsNotFound(err) {
123+
return nil, err
124+
}
125+
cm = &v1.ConfigMap{
126+
ObjectMeta: metav1.ObjectMeta{
127+
Name: name,
128+
Labels: labels,
129+
},
130+
}
131+
log.Infof("About to craete ConfigMap %v/%v for proxy", namespace, cm.Name)
132+
return f.client.CoreV1().ConfigMaps(namespace).Create(cm)
133+
}
134+
135+
func (f *nginx) updateConfig(lb *lbapi.LoadBalancer, cm *v1.ConfigMap) error {
136+
// 1. if cm has unmanaged config, we should generate cm.Data with old method
137+
done, err := f.updateIfHasUnmanagedConfig(lb, cm)
138+
if err != nil || done {
95139
return err
96140
}
97141

98-
if errors.IsNotFound(err) {
99-
cm = &v1.ConfigMap{
100-
ObjectMeta: metav1.ObjectMeta{
101-
Name: name,
102-
Labels: labels,
103-
},
104-
Data: data,
105-
}
106-
log.Infof("About to craete ConfigMap %v/%v for proxy", namespace, cm.Name)
107-
_, nerr := f.client.CoreV1().ConfigMaps(namespace).Create(cm)
108-
if nerr != nil {
109-
return nerr
110-
}
142+
// 2. otherwise, use new method that generate cm.Data by external configs
143+
//externalConfigMaps, preset, override, err := f.getExternalConfig(lb)
144+
externalConfigMaps, preset, override, err := f.getExternalConfig(lb)
145+
if err != nil {
146+
return err
111147
}
148+
newConfig := mapAdd(preset, defaultConfig, lb.Spec.Proxy.Config, override)
149+
bs, _ := json.Marshal(externalConfigMaps)
150+
externalConfigMapsStr := string(bs)
112151

113-
if data == nil {
114-
// do not update data if data == nil
115-
// tcp and udp config map will be changed by others
116-
// the controller only need to create it
152+
if reflect.DeepEqual(cm.Data, newConfig) && externalConfigMapsStr == cm.Annotations[annotationExternalConfigMaps] {
117153
return nil
118154
}
119155

120-
data = merge(cm.Data, del, data)
156+
if cm.Annotations == nil {
157+
cm.Annotations = make(map[string]string)
158+
}
159+
cm.Annotations[annotationExternalConfigMaps] = externalConfigMapsStr
160+
cm.Data = newConfig
161+
log.Infof("About to update ConfigMap %v/%v data, with exnternal configs: %v", cm.Namespace, cm.Name, externalConfigMapsStr)
162+
_, err = f.client.CoreV1().ConfigMaps(cm.Namespace).Update(cm)
163+
return err
164+
}
121165

122-
if reflect.DeepEqual(cm.Data, data) {
123-
return nil
166+
func (f *nginx) updateIfHasUnmanagedConfig(lb *lbapi.LoadBalancer, cm *v1.ConfigMap) (bool, error) {
167+
var err error
168+
169+
var oldExternalConfigMaps []string
170+
if value, ok := cm.Annotations[annotationExternalConfigMaps]; ok {
171+
err = json.Unmarshal([]byte(value), &oldExternalConfigMaps)
172+
if err != nil {
173+
return false, err
174+
}
175+
}
176+
177+
var unmanagedConifgs map[string]string
178+
// we consider that configs may contains unmanaged config only if cm is not marked (oldExternalConfigMaps is empty).
179+
if len(oldExternalConfigMaps) == 0 {
180+
unmanagedConifgs = mapDel(cm.Data, defaultConfig, managedConfig)
181+
}
182+
183+
// if unmanagedConifgs is empty, we can update configs with new method safetly.
184+
// otherwise, we should keep using old method to not lose user's unmanaged conifgs.
185+
if len(unmanagedConifgs) == 0 {
186+
return false, nil
124187
}
125188

126-
// replace cm.Data of data
127-
// the data follows the priority
128-
// 1. lb.Spec.Proxy.Config
129-
// 2. default config
130-
cm.Data = data
131-
log.Infof("About to update ConfigMap %v/%v data", namespace, cm.Name)
132-
_, err = f.client.CoreV1().ConfigMaps(namespace).Update(cm)
189+
log.Warningf("Found unmanaged configs in %s/%s: %v", lb.Namespace, lb.Name, unmanagedConifgs)
190+
newConfig := mapAdd(unmanagedConifgs, defaultConfig, lb.Spec.Proxy.Config)
133191

134-
return err
192+
if !reflect.DeepEqual(cm.Data, newConfig) {
193+
cm.Data = newConfig
194+
log.Warningf("About to update ConfigMap %v/%v data with old method", cm.Namespace, cm.Name)
195+
_, err = f.client.CoreV1().ConfigMaps(cm.Namespace).Update(cm)
196+
}
197+
return true, err
198+
}
199+
200+
func (f *nginx) getExternalConfig(lb *lbapi.LoadBalancer) ([]string, map[string]string, map[string]string, error) {
201+
202+
presetConfigMaps := []string{}
203+
overrideConfigMaps := []string{}
204+
presetConfig := make(map[string]string)
205+
overrideConfig := make(map[string]string)
206+
207+
for _, scope := range []string{"platform", "cluster", "instance-%s"} {
208+
209+
for _, postfix := range []string{"", "-override"} {
210+
name := fmt.Sprintf("cfg-lb-nginx-%s%s", scope, postfix)
211+
if scope == "instance-%s" {
212+
name = fmt.Sprintf(name, lb.Name)
213+
}
214+
cm, err := f.client.CoreV1().ConfigMaps(lb.Namespace).Get(name, metav1.GetOptions{})
215+
if errors.IsNotFound(err) {
216+
continue
217+
}
218+
if err != nil {
219+
return nil, nil, nil, err
220+
}
221+
222+
if postfix == "" {
223+
presetConfig = mapAdd(presetConfig, cm.Data)
224+
presetConfigMaps = append(presetConfigMaps, cm.Name)
225+
continue
226+
}
227+
overrideConfig = mapAdd(overrideConfig, cm.Data)
228+
overrideConfigMaps = append(overrideConfigMaps, cm.Name)
229+
}
230+
}
231+
232+
presetConfigMaps = append(presetConfigMaps, "") // empty string delimits 'preset' and 'override'
233+
presetConfigMaps = append(presetConfigMaps, overrideConfigMaps...)
234+
return presetConfigMaps, presetConfig, overrideConfig, nil
135235
}

0 commit comments

Comments
 (0)